]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds-tool: expose new signed PCR policies in creds tool, too
authorLennart Poettering <lennart@poettering.net>
Wed, 17 Aug 2022 15:28:49 +0000 (17:28 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 8 Sep 2022 14:34:27 +0000 (16:34 +0200)
man/systemd-creds.xml
src/creds/creds.c

index 7592961f63306b03030d8bca3d60205269fdb197..d9b30a7e96a29158cab658609c85de2ef25b6585 100644 (file)
         <citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--tpm2-public-key=</option><arg>PATH</arg></term>
+        <term><option>--tpm2-public-key-pcrs=</option><arg rep="repeat">PCR</arg></term>
+
+        <listitem><para>Configures a TPM2 signed PCR policy to bind encryption to, for use with the
+        <command>encrypt</command> command. The <option>--tpm2-public-key=</option> option accepts a path to
+        a PEM encoded RSA public key, to bind the encryption to. If this is not specified explicitly, but a
+        file <filename>tpm2-pcr-public-key.pem</filename> exists in one of the directories
+        <filename>/etc/systemd/</filename>, <filename>/run/systemd/</filename>,
+        <filename>/usr/lib/systemd/</filename> (searched in this order), it is automatically used. The
+        <option>--tpm2-public-key-pcrs=</option> option takes a list of TPM2 PCR indexes to bind to (same
+        syntax as <option>--tpm2-pcrs=</option> described above). If not specified defaults to 11 (i.e. this
+        binds the policy to any unified kernel image for which a PCR signature can be provided).</para>
+
+        <para>Note the difference between <option>--tpm2-pcrs=</option> and
+        <option>--tpm2-public-key-pcrs=</option>: the former binds decryption to the current, specific PCR
+        values; the latter binds decryption to any set of PCR values for which a signature by the specified
+        public key can be provided. The latter is hence more useful in scenarios where software updates shall
+        be possible without losing access to all previously encrypted secrets.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--tpm2-signature=</option><arg>PATH</arg></term>
+
+        <listitem><para>Takes a path to a TPM2 PCR signature file as generated by the
+        <citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        tool and that may be used to allow the <command>decrypt</command> command to decrypt credentials that
+        are bound to specific signed PCR values. If this this is not specified explicitly, and a credential
+        with a signed PCR policy is attempted to be decrypted, a suitable signature file
+        <filename>tpm2-pcr-signature.json</filename> is searched for in <filename>/etc/systemd/</filename>,
+        <filename>/run/systemd/</filename>, <filename>/usr/lib/systemd/</filename> (in this order) and
+        used.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--quiet</option></term>
         <term><option>-q</option></term>
@@ -413,7 +447,8 @@ SetCredentialEncrypted=mysql-password: \
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-measure</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 03422d31ff43e67d2766f0d4785d0e1d714b8719..5586fd776a817fc5ac8a463e50723a24f99423f6 100644 (file)
@@ -21,6 +21,7 @@
 #include "stat-util.h"
 #include "string-table.h"
 #include "terminal-util.h"
+#include "tpm-pcr.h"
 #include "tpm2-util.h"
 #include "verbs.h"
 
@@ -43,6 +44,9 @@ static int arg_newline = -1;
 static sd_id128_t arg_with_key = _CRED_AUTO;
 static const char *arg_tpm2_device = NULL;
 static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
+static char *arg_tpm2_public_key = NULL;
+static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
+static char *arg_tpm2_signature = NULL;
 static const char *arg_name = NULL;
 static bool arg_name_any = false;
 static usec_t arg_timestamp = USEC_INFINITY;
@@ -50,6 +54,9 @@ static usec_t arg_not_after = USEC_INFINITY;
 static bool arg_pretty = false;
 static bool arg_quiet = false;
 
+STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
+
 static const char* transcode_mode_table[_TRANSCODE_MAX] = {
         [TRANSCODE_OFF] = "off",
         [TRANSCODE_BASE64] = "base64",
@@ -418,7 +425,7 @@ static int verb_cat(int argc, char **argv, void *userdata) {
                                         *cn,
                                         timestamp,
                                         arg_tpm2_device,
-                                        /* tpm2_signature_path= */ NULL,
+                                        arg_tpm2_signature,
                                         data, size,
                                         &plaintext, &plaintext_size);
                         if (r < 0)
@@ -491,8 +498,8 @@ static int verb_encrypt(int argc, char **argv, void *userdata) {
                         arg_not_after,
                         arg_tpm2_device,
                         arg_tpm2_pcr_mask,
-                        /* tpm2_pubkey_path= */ NULL,
-                        /* tpm2_pubkey_pcr_mask= */ 0,
+                        arg_tpm2_public_key,
+                        arg_tpm2_public_key_pcr_mask,
                         plaintext, plaintext_size,
                         &output, &output_size);
         if (r < 0)
@@ -580,7 +587,7 @@ static int verb_decrypt(int argc, char **argv, void *userdata) {
                         name,
                         timestamp,
                         arg_tpm2_device,
-                        /* tpm2_signature_path= */ NULL,
+                        arg_tpm2_signature,
                         input, input_size,
                         &plaintext, &plaintext_size);
         if (r < 0)
@@ -686,7 +693,13 @@ static int verb_help(int argc, char **argv, void *userdata) {
                "     --tpm2-device=PATH\n"
                "                          Pick TPM2 device\n"
                "     --tpm2-pcrs=PCR1+PCR2+PCR3+…\n"
-               "                          Specify TPM2 PCRs to seal against\n"
+               "                          Specify TPM2 PCRs to seal against (fixed hash)\n"
+               "     --tpm2-public-key=PATH\n"
+               "                          Specify PEM certificate to seal against\n"
+               "     --tpm2-public-key-pcrs=PCR1+PCR2+PCR3+…\n"
+               "                          Specify TPM2 PCRs to seal against (public key)\n"
+               "     --tpm2-signature=PATH\n"
+               "                          Specify signature for public key PCR policy\n"
                "  -q --quiet              Suppress output for 'has-tpm2' verb\n"
                "\nSee the %2$s for details.\n"
                , program_invocation_short_name
@@ -711,28 +724,34 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_WITH_KEY,
                 ARG_TPM2_DEVICE,
                 ARG_TPM2_PCRS,
+                ARG_TPM2_PUBLIC_KEY,
+                ARG_TPM2_PUBLIC_KEY_PCRS,
+                ARG_TPM2_SIGNATURE,
                 ARG_NAME,
                 ARG_TIMESTAMP,
                 ARG_NOT_AFTER,
         };
 
         static const struct option options[] = {
-                { "help",        no_argument,       NULL, 'h'             },
-                { "version",     no_argument,       NULL, ARG_VERSION     },
-                { "no-pager",    no_argument,       NULL, ARG_NO_PAGER    },
-                { "no-legend",   no_argument,       NULL, ARG_NO_LEGEND   },
-                { "json",        required_argument, NULL, ARG_JSON        },
-                { "system",      no_argument,       NULL, ARG_SYSTEM      },
-                { "transcode",   required_argument, NULL, ARG_TRANSCODE   },
-                { "newline",     required_argument, NULL, ARG_NEWLINE     },
-                { "pretty",      no_argument,       NULL, 'p'             },
-                { "with-key",    required_argument, NULL, ARG_WITH_KEY    },
-                { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
-                { "tpm2-pcrs",   required_argument, NULL, ARG_TPM2_PCRS   },
-                { "name",        required_argument, NULL, ARG_NAME        },
-                { "timestamp",   required_argument, NULL, ARG_TIMESTAMP   },
-                { "not-after",   required_argument, NULL, ARG_NOT_AFTER   },
-                { "quiet",       no_argument,       NULL, 'q'             },
+                { "help",                 no_argument,       NULL, 'h'                      },
+                { "version",              no_argument,       NULL, ARG_VERSION              },
+                { "no-pager",             no_argument,       NULL, ARG_NO_PAGER             },
+                { "no-legend",            no_argument,       NULL, ARG_NO_LEGEND            },
+                { "json",                 required_argument, NULL, ARG_JSON                 },
+                { "system",               no_argument,       NULL, ARG_SYSTEM               },
+                { "transcode",            required_argument, NULL, ARG_TRANSCODE            },
+                { "newline",              required_argument, NULL, ARG_NEWLINE              },
+                { "pretty",               no_argument,       NULL, 'p'                      },
+                { "with-key",             required_argument, NULL, ARG_WITH_KEY             },
+                { "tpm2-device",          required_argument, NULL, ARG_TPM2_DEVICE          },
+                { "tpm2-pcrs",            required_argument, NULL, ARG_TPM2_PCRS            },
+                { "tpm2-public-key",      required_argument, NULL, ARG_TPM2_PUBLIC_KEY      },
+                { "tpm2-public-key-pcrs", required_argument, NULL, ARG_TPM2_PUBLIC_KEY_PCRS },
+                { "tpm2-signature",       required_argument, NULL, ARG_TPM2_SIGNATURE       },
+                { "name",                 required_argument, NULL, ARG_NAME                 },
+                { "timestamp",            required_argument, NULL, ARG_TIMESTAMP            },
+                { "not-after",            required_argument, NULL, ARG_NOT_AFTER            },
+                { "quiet",                no_argument,       NULL, 'q'                      },
                 {}
         };
 
@@ -812,8 +831,12 @@ static int parse_argv(int argc, char *argv[]) {
                                 arg_with_key = CRED_AES256_GCM_BY_HOST;
                         else if (streq(optarg, "tpm2"))
                                 arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC;
+                        else if (streq(optarg, "tpm2-with-public-key"))
+                                arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC_WITH_PK;
                         else if (STR_IN_SET(optarg, "host+tpm2", "tpm2+host"))
                                 arg_with_key = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC;
+                        else if (STR_IN_SET(optarg, "host+tpm2-with-public-key", "tpm2-with-public-key+host"))
+                                arg_with_key = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC_WITH_PK;
                         else if (streq(optarg, "tpm2-absent"))
                                 arg_with_key = CRED_AES256_GCM_BY_TPM2_ABSENT;
                         else
@@ -836,13 +859,34 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_tpm2_device = streq(optarg, "auto") ? NULL : optarg;
                         break;
 
-                case ARG_TPM2_PCRS:
+                case ARG_TPM2_PCRS: /* For fixed hash PCR policies only */
                         r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_pcr_mask);
                         if (r < 0)
                                 return r;
 
                         break;
 
+                case ARG_TPM2_PUBLIC_KEY:
+                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_tpm2_public_key);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
+                case ARG_TPM2_PUBLIC_KEY_PCRS: /* For public key PCR policies only */
+                        r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_public_key_pcr_mask);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
+                case ARG_TPM2_SIGNATURE:
+                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_tpm2_signature);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
                 case ARG_NAME:
                         if (isempty(optarg)) {
                                 arg_name = NULL;
@@ -885,6 +929,8 @@ static int parse_argv(int argc, char *argv[]) {
 
         if (arg_tpm2_pcr_mask == UINT32_MAX)
                 arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT;
+        if (arg_tpm2_public_key_pcr_mask == UINT32_MAX)
+                arg_tpm2_public_key_pcr_mask = UINT32_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE;
 
         return 1;
 }