<xi:include href="version-info.xml" xpointer="v252"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--private-key-uri=</option></term>
+
+ <listitem><para>Takes a URI-like string referring to a private key, that will be passed to OpenSSL's
+ "engine" or "provider" logic. Configures the signing key to use when creating verity signature
+ partitions with the <varname>Verity=signature</varname> setting in partition files.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--certificate=</option></term>
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</example>
+ <example>
+ <title>Generate a system extension image and sign it via PKCS11</title>
+
+ <para>The following creates a system extension DDI (sysext) for an
+ <filename>/usr/foo</filename> update and signs it with a hardware token via PKCS11.</para>
+
+ <programlisting>mkdir tree tree/usr tree/usr/lib/extension-release.d
+echo "Hello World" > tree/usr/foo
+cat > tree/usr/lib/extension-release.d/extension-release.my-foo <<EOF
+ID=fedora
+VERSION_ID=38
+IMAGE_ID=my-foo
+IMAGE_VERSION=7
+EOF
+systemd-repart --make-ddi=sysext --private-key-uri="pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=0123456789abcdef;token=Some%20Cert" --certificate=cert.crt -s tree/ /var/lib/extensions/my-foo.sysext.raw
+systemd-sysext refresh</programlisting>
+
+ <para>The DDI generated that way may be applied to the system with
+ <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
+ </example>
+
</refsect1>
<refsect1>
}
static int parse_argv(int argc, char *argv[]) {
+ _cleanup_free_ char *private_key = NULL, *private_key_uri = NULL;
enum {
ARG_VERSION = 0x100,
ARG_JSON,
ARG_KEY_FILE,
ARG_PRIVATE_KEY,
+ ARG_PRIVATE_KEY_URI,
ARG_CERTIFICATE,
ARG_TPM2_DEVICE,
ARG_TPM2_DEVICE_KEY,
{ "json", required_argument, NULL, ARG_JSON },
{ "key-file", required_argument, NULL, ARG_KEY_FILE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
+ { "private-key-uri", required_argument, NULL, ARG_PRIVATE_KEY_URI },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-device-key", required_argument, NULL, ARG_TPM2_DEVICE_KEY },
}
case ARG_PRIVATE_KEY: {
- _cleanup_(erase_and_freep) char *k = NULL;
- size_t n = 0;
-
- r = read_full_file_full(
- AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
- NULL,
- &k, &n);
+ r = free_and_strdup_warn(&private_key, optarg);
if (r < 0)
- return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
+ return r;
+ break;
+ }
- EVP_PKEY_free(arg_private_key);
- arg_private_key = NULL;
- r = parse_private_key(k, n, &arg_private_key);
+ case ARG_PRIVATE_KEY_URI: {
+ r = free_and_strdup_warn(&private_key_uri, optarg);
if (r < 0)
return r;
break;
*p = gpt_partition_type_override_architecture(*p, arg_architecture);
}
+ if (private_key && private_key_uri)
+ return log_error_errno(
+ SYNTHETIC_ERRNO(EINVAL),
+ "Cannot specify both --private-key= and --private-key-uri=.");
+
+ if (private_key) {
+ _cleanup_(erase_and_freep) char *k = NULL;
+ size_t n = 0;
+
+ r = read_full_file_full(
+ AT_FDCWD, private_key, UINT64_MAX, SIZE_MAX,
+ READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+ NULL,
+ &k, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read key file '%s': %m", private_key);
+
+ r = parse_private_key(k, n, &arg_private_key);
+ if (r < 0)
+ return r;
+ } else if (private_key_uri) {
+ /* This must happen after parse_x509_certificate() is called above, otherwise
+ * signing later will get stuck as the parsed private key won't have the
+ * certificate, so this block cannot be inline in ARG_PRIVATE_KEY. */
+ r = openssl_load_key_from_token(private_key_uri, &arg_private_key);
+ if (r < 0)
+ return log_error_errno(
+ r,
+ "Failed to load key '%s' from OpenSSL provider: %m",
+ private_key);
+ }
+
return 1;
}