* `$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
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported public key type: %s", OBJ_nid2sn(type));
}
}
+
+static int load_key_from_provider(const char *provider, const char *private_key_uri, EVP_PKEY **ret) {
+
+ assert(provider);
+ assert(private_key_uri);
+ assert(ret);
+
+#if OPENSSL_VERSION_MAJOR >= 3
+ /* Load the provider so that this can work without any custom written configuration in /etc/.
+ * Also load the 'default' as that seems to be the recommendation. */
+ if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
+ return log_openssl_errors("Failed to load OpenSSL provider '%s'", provider);
+ if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
+ return log_openssl_errors("Failed to load OpenSSL provider 'default'");
+
+ _cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
+ private_key_uri,
+ /* ui_method= */ NULL,
+ /* ui_data= */ NULL,
+ /* post_process= */ NULL,
+ /* post_process_data= */ NULL);
+ if (!store)
+ return log_openssl_errors("Failed to open OpenSSL store via '%s'", private_key_uri);
+
+ _cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = OSSL_STORE_load(store);
+ if (!info)
+ return log_openssl_errors("Failed to load OpenSSL store via '%s'", private_key_uri);
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = OSSL_STORE_INFO_get1_PKEY(info);
+ if (!private_key)
+ return log_openssl_errors("Failed to load private key via '%s'", private_key_uri);
+
+ *ret = TAKE_PTR(private_key);
+
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
+}
+
+static int load_key_from_engine(const char *engine, const char *private_key_uri, EVP_PKEY **ret) {
+
+ assert(engine);
+ assert(private_key_uri);
+ assert(ret);
+
+ DISABLE_WARNING_DEPRECATED_DECLARATIONS;
+ _cleanup_(ENGINE_freep) ENGINE *e = ENGINE_by_id(engine);
+ if (!e)
+ return log_openssl_errors("Failed to load signing engine '%s'", engine);
+
+ if (ENGINE_init(e) == 0)
+ return log_openssl_errors("Failed to initialize signing engine '%s'", engine);
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(
+ e,
+ private_key_uri,
+ /* ui_method= */ NULL,
+ /* callback_data= */ NULL);
+ if (!private_key)
+ return log_openssl_errors("Failed to load private key from '%s'", private_key_uri);
+ REENABLE_WARNING;
+
+ *ret = TAKE_PTR(private_key);
+
+ 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);
+
+ colon = strchr(private_key_uri, ':');
+ if (!colon)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid URI '%s'", private_key_uri);
+
+ provider = strndup(private_key_uri, colon - private_key_uri);
+ if (!provider)
+ return log_oom_debug();
+
+ 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);
+ }
+ }
+
+ return r;
+}
#endif
int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
# include <openssl/bio.h>
# include <openssl/bn.h>
# include <openssl/crypto.h>
+# include <openssl/engine.h>
# include <openssl/err.h>
# include <openssl/evp.h>
# include <openssl/opensslv.h>
# include <openssl/core_names.h>
# include <openssl/kdf.h>
# include <openssl/param_build.h>
+# include <openssl/provider.h>
+# include <openssl/store.h>
# endif
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(void*, OPENSSL_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD_CTX*, EVP_MD_CTX_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ASN1_OCTET_STRING*, ASN1_OCTET_STRING_free, NULL);
+DISABLE_WARNING_DEPRECATED_DECLARATIONS;
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ENGINE*, ENGINE_free, NULL);
+REENABLE_WARNING;
#if OPENSSL_VERSION_MAJOR >= 3
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER*, EVP_CIPHER_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_KDF*, EVP_KDF_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD*, EVP_MD_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_PARAM*, OSSL_PARAM_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_PARAM_BLD*, OSSL_PARAM_BLD_free, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_STORE_CTX*, OSSL_STORE_close, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_STORE_INFO*, OSSL_STORE_INFO_free, NULL);
#else
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(HMAC_CTX*, HMAC_CTX_free, NULL);
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);
+
#else
typedef struct X509 X509;
return NULL;
}
+static inline int openssl_load_key_from_token(const char *private_key_uri, EVP_PKEY **ret) {
+ return -EOPNOTSUPP;
+}
+
#endif
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);