]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
measure: add --append= switch for merging signatures
authorLennart Poettering <lennart@poettering.net>
Tue, 1 Nov 2022 13:54:47 +0000 (14:54 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 15 Dec 2022 10:40:21 +0000 (11:40 +0100)
Often it's useful to add multiple signatures in the signature JSON file
to embedd in a single .pcrsig. (For example, a signature by key X for
boot phase "enter-initrd" and one by key Y for
"enter-initrd:leave-initrd" or so). Make this easy, by adding the
ability to append signatures to a previously generated JSON file.

man/systemd-measure.xml
src/boot/measure.c

index f3b2834b2ec23274c7f7ce5df91c1d2bc7727453..998ae33d992d9df2cf2423fa169ff6c0d4ab4c13 100644 (file)
         <citerefentry><refentrytitle>systemd-pcrphase.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--append=</option><replaceable>PATH</replaceable></term>
+
+        <listitem><para>When generating a PCR JSON signature (via the <command>sign</command> command),
+        combine it with a previously generated PCR JSON signature, and output it as one. The specified path
+        must refer to a regular file that contains a valid JSON PCR signature object. The specified file is
+        not modified. It will be read first, then the newly generated signature appended to it, and the
+        resulting object is written to standard output. Use this to generate a single JSON object consisting
+        from signatures made with a number of signing keys (for example, to have one key per boot phase). The
+        command will suppress duplicates: if a specific signature is already included in a JSON signature
+        object it is not added a second time.</para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="json" />
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
index 913cf18ee6ef554213f19aa31c73636b7d49600c..4ee5b1de3b1a5eeabd20c7ff24583525b3c1c0b3 100644 (file)
@@ -33,12 +33,14 @@ static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORM
 static PagerFlags arg_pager_flags = 0;
 static bool arg_current = false;
 static char **arg_phase = NULL;
+static char *arg_append = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_banks, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_public_key, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_phase, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_append, freep);
 
 static inline void free_sections(char*(*sections)[_UNIFIED_SECTION_MAX]) {
         for (UnifiedSection c = 0; c < _UNIFIED_SECTION_MAX; c++)
@@ -73,6 +75,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --public-key=KEY    Public key (PEM) to validate against\n"
                "     --json=MODE         Output as JSON\n"
                "  -j                     Same as --json=pretty on tty, --json=short otherwise\n"
+               "     --append=PATH       Load specified JSON signature, and append new signature to it\n"
                "\n%3$sUKI PE Section Options:%4$s                                         %3$sUKI PE Section%4$s\n"
                "     --linux=PATH        Path to Linux kernel image file        %7$s .linux\n"
                "     --osrel=PATH        Path to os-release file                %7$s .osrel\n"
@@ -128,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_TPM2_DEVICE,
                 ARG_JSON,
                 ARG_PHASE,
+                ARG_APPEND,
         };
 
         static const struct option options[] = {
@@ -148,6 +152,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "public-key",  required_argument, NULL, ARG_PUBLIC_KEY  },
                 { "json",        required_argument, NULL, ARG_JSON        },
                 { "phase",       required_argument, NULL, ARG_PHASE       },
+                { "append",      required_argument, NULL, ARG_APPEND      },
                 {}
         };
 
@@ -254,6 +259,13 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
+                case ARG_APPEND:
+                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_append);
+                        if (r < 0)
+                                return r;
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -623,6 +635,8 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
 
         if (!arg_sections[UNIFIED_SECTION_LINUX] && !arg_current)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Either --linux= or --current must be specified, refusing.");
+        if (arg_append)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The --append= switch is only supported for 'sign', not 'calculate'.");
 
         assert(!strv_isempty(arg_banks));
         assert(!strv_isempty(arg_phase));
@@ -728,6 +742,15 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
         assert(!strv_isempty(arg_banks));
         assert(!strv_isempty(arg_phase));
 
+        if (arg_append) {
+                r = json_parse_file(NULL, arg_append, 0, &v, NULL, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse '%s': %m", arg_append);
+
+                if (!json_variant_is_object(v))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File '%s' is not a valid JSON object, refusing.", arg_append);
+        }
+
         /* When signing we only support JSON output */
         arg_json_format_flags &= ~JSON_FORMAT_OFF;
 
@@ -936,7 +959,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
                         _cleanup_(json_variant_unrefp) JsonVariant *av = NULL;
                         av = json_variant_ref(json_variant_by_key(v, p->bank));
 
-                        r = json_variant_append_array(&av, bv);
+                        r = json_variant_append_array_nodup(&av, bv);
                         if (r < 0) {
                                 log_error_errno(r, "Failed to append JSON object: %m");
                                 goto finish;