]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: support OpenSSL engines/providers for signing 31261/head
authorLuca Boccassi <bluca@debian.org>
Wed, 11 Oct 2023 18:23:40 +0000 (19:23 +0100)
committerLuca Boccassi <bluca@debian.org>
Fri, 9 Feb 2024 15:11:25 +0000 (15:11 +0000)
The provider API which is new requires providers, which are not
widely available and don't work very well yet, so also use a
fallback with the legacy engine API.

man/systemd-repart.xml
src/partition/repart.c

index b645027ee3609d10d744563010a9531774b88036..da5d5858459b3a638b333b4f0dd5484829a036e2 100644 (file)
         <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>
 
@@ -616,6 +626,27 @@ systemd-confext refresh</programlisting>
       <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 &lt;&lt;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>
index 05332f9680f5ced5c52791a1f93814198814a5f9..6f347a6e1faaada10ddebf6d4a5a980018f0f9b9 100644 (file)
@@ -6506,6 +6506,7 @@ static int help(void) {
 }
 
 static int parse_argv(int argc, char *argv[]) {
+        _cleanup_free_ char *private_key = NULL, *private_key_uri = NULL;
 
         enum {
                 ARG_VERSION = 0x100,
@@ -6526,6 +6527,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_JSON,
                 ARG_KEY_FILE,
                 ARG_PRIVATE_KEY,
+                ARG_PRIVATE_KEY_URI,
                 ARG_CERTIFICATE,
                 ARG_TPM2_DEVICE,
                 ARG_TPM2_DEVICE_KEY,
@@ -6566,6 +6568,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "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      },
@@ -6751,20 +6754,14 @@ static int parse_argv(int argc, char *argv[]) {
                 }
 
                 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;
@@ -7101,6 +7098,38 @@ static int parse_argv(int argc, char *argv[]) {
                         *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;
 }