]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: add --private-key-source and drop --private-key-uri
authorLuca Boccassi <bluca@debian.org>
Sun, 11 Feb 2024 20:15:51 +0000 (20:15 +0000)
committerLuca Boccassi <bluca@debian.org>
Fri, 1 Mar 2024 17:32:19 +0000 (17:32 +0000)
It turns out it's mostly PKCS11 that supports the URI format,
and other engines just take files. For example the tpm2-tss-openssl
engine just takes a sealed private key file path as the key input,
and the engine needs to be specified separately.

Add --private-key-source=file|engine:foo|provider:bar to
manually specify how to use the private key parameter.

Follow-up for 0a8264080a5d4b5e13e65eed80ac98a476f7fe43

docs/ENVIRONMENT.md
man/systemd-repart.xml
src/partition/repart.c
src/shared/openssl-util.c
src/shared/openssl-util.h

index 302ca67b576d4bbee0c94ff3eb54f82d534c9999..00492829bdc5dc565a4eeb4e2d4cce83d82758dd 100644 (file)
@@ -129,14 +129,6 @@ All tools:
 * `$SYSTEMD_VERITY_SHARING=0` — if set, sharing dm-verity devices by
   using a stable `<ROOTHASH>-verity` device mapper name will be disabled.
 
-* `$SYSTEMD_OPENSSL_KEY_LOADER`— when using OpenSSL to load a key via an engine
-  or a provider, can be used to force the usage of one or the other interface.
-  Set to 'engine' to force the usage of the old engine API, and to 'provider'
-  force the usage of the new provider API. If unset, the provider will be tried
-  first and the engine as a fallback if that fails. Providers are the new OpenSSL
-  3 API, but there are very few if any in a production-ready state, so engines
-  are still needed.
-
 `systemctl`:
 
 * `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID 1's private D-Bus
index 7dfcfc90b31c80ebf23aa0065fe4d9725d171e02..7e2730a33a2baf0fde1f76bea802bc6ef19665e9 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><option>--private-key-uri=</option></term>
+        <term><option>--private-key-source=</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>
+        <listitem><para>Takes one of <literal>file</literal>, <literal>engine</literal> or
+        <literal>provider</literal>. In the latter two cases, it is followed by the name of a provider or
+        engine, separated by colon, that will be passed to OpenSSL's "engine" or "provider" logic.
+        Configures the signing mechanism 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>
@@ -662,7 +664,7 @@ 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-repart --make-ddi=sysext --private-key-source=engine:pkcs11 --private-key="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
index db1d00974e3771058b7122b58b8da69689fe65f7..54ded64aee952e9d28c6e3d327fa8cb2e98b4169 100644 (file)
@@ -146,6 +146,8 @@ static bool arg_legend = true;
 static void *arg_key = NULL;
 static size_t arg_key_size = 0;
 static EVP_PKEY *arg_private_key = NULL;
+static KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
+static char *arg_private_key_source = NULL;
 static X509 *arg_certificate = NULL;
 static char *arg_tpm2_device = NULL;
 static uint32_t arg_tpm2_seal_key_handle = 0;
@@ -177,6 +179,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep);
@@ -6806,8 +6809,14 @@ static int help(void) {
                "                          Specify disk image dissection policy\n"
                "     --definitions=DIR    Find partition definitions in specified directory\n"
                "     --key-file=PATH      Key to use when encrypting partitions\n"
-               "     --private-key=PATH   Private key to use when generating verity roothash\n"
-               "                          signatures\n"
+               "     --private-key=PATH|URI\n"
+               "                          Private key to use when generating verity roothash\n"
+               "                          signatures, or an engine or provider specific\n"
+               "                          designation if --private-key-source= is used.\n"
+               "     --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
+               "                          Specify how to use the --private-key=. Allows to use\n"
+               "                          an OpenSSL engine/provider when generating verity\n"
+               "                          roothash signatures\n"
                "     --certificate=PATH   PEM certificate to use when generating verity\n"
                "                          roothash signatures\n"
                "     --tpm2-device=PATH   Path to TPM2 device node to use\n"
@@ -6857,7 +6866,7 @@ static int help(void) {
 }
 
 static int parse_argv(int argc, char *argv[]) {
-        _cleanup_free_ char *private_key = NULL, *private_key_uri = NULL;
+        _cleanup_free_ char *private_key = NULL;
 
         enum {
                 ARG_VERSION = 0x100,
@@ -6878,7 +6887,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_JSON,
                 ARG_KEY_FILE,
                 ARG_PRIVATE_KEY,
-                ARG_PRIVATE_KEY_URI,
+                ARG_PRIVATE_KEY_SOURCE,
                 ARG_CERTIFICATE,
                 ARG_TPM2_DEVICE,
                 ARG_TPM2_DEVICE_KEY,
@@ -6921,7 +6930,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      },
+                { "private-key-source",   required_argument, NULL, ARG_PRIVATE_KEY_SOURCE   },
                 { "certificate",          required_argument, NULL, ARG_CERTIFICATE          },
                 { "tpm2-device",          required_argument, NULL, ARG_TPM2_DEVICE          },
                 { "tpm2-device-key",      required_argument, NULL, ARG_TPM2_DEVICE_KEY      },
@@ -7115,12 +7124,14 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_PRIVATE_KEY_URI: {
-                        r = free_and_strdup_warn(&private_key_uri, optarg);
+                case ARG_PRIVATE_KEY_SOURCE:
+                        r = parse_openssl_key_source_argument(
+                                        optarg,
+                                        &arg_private_key_source,
+                                        &arg_private_key_source_type);
                         if (r < 0)
                                 return r;
                         break;
-                }
 
                 case ARG_CERTIFICATE: {
                         _cleanup_free_ char *cert = NULL;
@@ -7465,12 +7476,7 @@ 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) {
+        if (private_key && arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
                 _cleanup_(erase_and_freep) char *k = NULL;
                 size_t n = 0;
 
@@ -7485,16 +7491,22 @@ static int parse_argv(int argc, char *argv[]) {
                 r = parse_private_key(k, n, &arg_private_key);
                 if (r < 0)
                         return r;
-        } else if (private_key_uri) {
+        } else if (private_key &&
+                   IN_SET(arg_private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER)) {
                 /* 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);
+                r = openssl_load_key_from_token(
+                                arg_private_key_source_type,
+                                arg_private_key_source,
+                                private_key,
+                                &arg_private_key);
                 if (r < 0)
                         return log_error_errno(
                                         r,
-                                        "Failed to load key '%s' from OpenSSL provider: %m",
-                                        private_key);
+                                        "Failed to load key '%s' from OpenSSL private key source %s: %m",
+                                        private_key,
+                                        arg_private_key_source);
         }
 
         return 1;
index e2386d0513d0fc2805327cf95d449eccb1e5b0ed..63c443cbfdde791216316737163abe35d2ebbaf9 100644 (file)
@@ -1366,38 +1366,25 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
         return 0;
 }
 
-int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret) {
-        _cleanup_free_ char *provider = NULL;
-        const char *colon, *e;
-        int r;
-
-        assert(private_key_uri);
+int openssl_load_key_from_token(
+                KeySourceType private_key_source_type,
+                const char *private_key_source,
+                const char *private_key,
+                EVP_PKEY **ret) {
 
-        colon = strchr(private_key_uri, ':');
-        if (!colon)
-                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid URI '%s'", private_key_uri);
+        assert(IN_SET(private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER));
+        assert(private_key_source);
+        assert(private_key);
 
-        provider = strndup(private_key_uri, colon - private_key_uri);
-        if (!provider)
-                return log_oom_debug();
+        switch (private_key_source_type) {
 
-        e = secure_getenv("SYSTEMD_OPENSSL_KEY_LOADER");
-        if (e) {
-                if (streq(e, "provider"))
-                        r = load_key_from_provider(provider, private_key_uri, ret);
-                else if (streq(e, "engine"))
-                        r = load_key_from_engine(provider, private_key_uri, ret);
-                else
-                        return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid value for SYSTEMD_OPENSSL_KEY_LOADER: %s", e);
-        } else {
-                r = load_key_from_provider(provider, private_key_uri, ret);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to load key from provider '%s', falling back to engine", provider);
-                        r = load_key_from_engine(provider, private_key_uri, ret);
-                }
+        case OPENSSL_KEY_SOURCE_ENGINE:
+                return load_key_from_engine(private_key_source, private_key, ret);
+        case OPENSSL_KEY_SOURCE_PROVIDER:
+                return load_key_from_provider(private_key_source, private_key, ret);
+        default:
+                assert_not_reached();
         }
-
-        return r;
 }
 #endif
 
@@ -1418,3 +1405,34 @@ int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
         return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate X509 fingerprint: %m");
 #endif
 }
+
+int parse_openssl_key_source_argument(
+                const char *argument,
+                char **private_key_source,
+                KeySourceType *private_key_source_type) {
+
+        KeySourceType type;
+        const char *e = NULL;
+        int r;
+
+        assert(argument);
+        assert(private_key_source);
+        assert(private_key_source_type);
+
+        if (streq(argument, "file"))
+                type = OPENSSL_KEY_SOURCE_FILE;
+        else if ((e = startswith(argument, "engine:")))
+                type = OPENSSL_KEY_SOURCE_ENGINE;
+        else if ((e = startswith(argument, "provider:")))
+                type = OPENSSL_KEY_SOURCE_PROVIDER;
+        else
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid private key source '%s'", argument);
+
+        r = free_and_strdup_warn(private_key_source, e);
+        if (r < 0)
+                return r;
+
+        *private_key_source_type = type;
+
+        return 0;
+}
index 8d7d4f8c9fbccf1ef8f32e10ec42f239131a9dd5..e5ecbad86d86cc721c78fff9e3e2fab23faa51d6 100644 (file)
@@ -5,6 +5,16 @@
 #include "macro.h"
 #include "sha256.h"
 
+typedef enum KeySourceType {
+        OPENSSL_KEY_SOURCE_FILE,
+        OPENSSL_KEY_SOURCE_ENGINE,
+        OPENSSL_KEY_SOURCE_PROVIDER,
+        _OPENSSL_KEY_SOURCE_MAX,
+        _OPENSSL_KEY_SOURCE_INVALID = -EINVAL,
+} KeySourceType;
+
+int parse_openssl_key_source_argument(const char *argument, char **private_key_source, KeySourceType *private_key_source_type);
+
 #define X509_FINGERPRINT_SIZE SHA256_DIGEST_SIZE
 
 #if HAVE_OPENSSL
@@ -123,7 +133,7 @@ int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_s
 
 int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_t size, void **ret, size_t *ret_size);
 
-int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret);
+int openssl_load_key_from_token(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, EVP_PKEY **ret);
 
 #else
 
@@ -140,7 +150,12 @@ static inline void *EVP_PKEY_free(EVP_PKEY *p) {
         return NULL;
 }
 
-static inline int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret) {
+static inline int openssl_load_key_from_token(
+                KeySourceType private_key_source_type,
+                const char *private_key_source,
+                const char *private_key,
+                EVP_PKEY **ret) {
+
         return -EOPNOTSUPP;
 }