1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-21 22:04:01 +03:00

openssl: add helper to load key from provider/engine

It's not the literal private key, but EVP_PKEY becomes a reference
to the engine/provider that OpenSSL knows how to use later
This commit is contained in:
Luca Boccassi 2023-10-12 10:22:20 +01:00
parent c505275476
commit dba0afa14e
3 changed files with 123 additions and 0 deletions

View File

@ -129,6 +129,14 @@ 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

View File

@ -1298,6 +1298,107 @@ int pkey_generate_volume_keys(
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]) {

View File

@ -11,6 +11,7 @@
# 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>
@ -25,6 +26,8 @@
# 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);
@ -41,6 +44,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_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);
@ -50,6 +56,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MAC_CTX*, EVP_MAC_CTX_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);
@ -115,6 +123,8 @@ 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);
#else
typedef struct X509 X509;
@ -130,6 +140,10 @@ 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) {
return -EOPNOTSUPP;
}
#endif
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);