<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" />
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++)
" --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"
ARG_TPM2_DEVICE,
ARG_JSON,
ARG_PHASE,
+ ARG_APPEND,
};
static const struct option options[] = {
{ "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 },
{}
};
break;
}
+ case ARG_APPEND:
+ r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_append);
+ if (r < 0)
+ return r;
+
+ break;
+
case '?':
return -EINVAL;
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));
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;
_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;