summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/boot/measure.c65
-rw-r--r--src/partition/repart.c174
-rw-r--r--src/shared/openssl-util.c220
-rw-r--r--src/shared/openssl-util.h43
4 files changed, 334 insertions, 168 deletions
diff --git a/src/boot/measure.c b/src/boot/measure.c
index 557e06b094..3c409f8bd9 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -6,6 +6,7 @@
#include "sd-json.h"
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "build.h"
#include "efi-loader.h"
#include "fd-util.h"
@@ -803,6 +804,7 @@ static int verb_calculate(int argc, char *argv[], void *userdata) {
static int verb_sign(int argc, char *argv[], void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL;
_cleanup_(X509_freep) X509 *certificate = NULL;
size_t n;
@@ -834,54 +836,31 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
/* This must be done before openssl_load_key_from_token() otherwise it will get stuck */
if (arg_certificate) {
- _cleanup_(BIO_freep) BIO *cb = NULL;
- _cleanup_free_ char *crt = NULL;
-
- r = read_full_file_full(
- AT_FDCWD, arg_certificate, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_CONNECT_SOCKET,
- /* bind_name= */ NULL,
- &crt, &n);
+ r = openssl_load_x509_certificate(arg_certificate, &certificate);
if (r < 0)
- return log_error_errno(r, "Failed to read certificate file '%s': %m", arg_certificate);
-
- cb = BIO_new_mem_buf(crt, n);
- if (!cb)
- return log_oom();
-
- certificate = PEM_read_bio_X509(cb, NULL, NULL, NULL);
- if (!certificate)
- return log_error_errno(
- SYNTHETIC_ERRNO(EBADMSG),
- "Failed to parse X.509 certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
}
- if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
- _cleanup_fclose_ FILE *privkeyf = NULL;
- _cleanup_free_ char *resolved_pkey = NULL;
+ if (arg_private_key) {
+ if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
+ r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
+ }
- r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &resolved_pkey);
+ r = openssl_load_private_key(
+ arg_private_key_source_type,
+ arg_private_key_source,
+ arg_private_key,
+ &(AskPasswordRequest) {
+ .id = "measure-private-key-pin",
+ .keyring = arg_private_key,
+ .credential = "measure.private-key-pin",
+ },
+ &privkey,
+ &ui);
if (r < 0)
- return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
-
- privkeyf = fopen(resolved_pkey, "re");
- if (!privkeyf)
- return log_error_errno(errno, "Failed to open private key file '%s': %m", resolved_pkey);
-
- privkey = PEM_read_PrivateKey(privkeyf, NULL, NULL, NULL);
- if (!privkey)
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse private key '%s'.", resolved_pkey);
- } else if (arg_private_key_source &&
- IN_SET(arg_private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER)) {
- r = openssl_load_key_from_token(
- arg_private_key_source_type, arg_private_key_source, arg_private_key, &privkey);
- if (r < 0)
- return log_error_errno(
- r,
- "Failed to load key '%s' from OpenSSL key source %s: %m",
- arg_private_key,
- arg_private_key_source);
+ return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
}
if (arg_public_key) {
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 8070b02cab..be5171d5e1 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -17,6 +17,7 @@
#include "sd-json.h"
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "blkid-util.h"
#include "blockdev-list.h"
#include "blockdev-util.h"
@@ -149,10 +150,10 @@ static PagerFlags arg_pager_flags = 0;
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 char *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_certificate = NULL;
static char *arg_tpm2_device = NULL;
static uint32_t arg_tpm2_seal_key_handle = 0;
static char *arg_tpm2_device_key = NULL;
@@ -182,9 +183,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
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, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
@@ -429,6 +430,9 @@ typedef struct Context {
int backing_fd;
bool from_scratch;
+
+ X509 *certificate;
+ EVP_PKEY *private_key;
} Context;
static const char *empty_mode_table[_EMPTY_MODE_MAX] = {
@@ -709,9 +713,11 @@ static Partition* partition_unlink_and_free(Context *context, Partition *p) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Partition*, partition_free);
-static Context* context_new(sd_id128_t seed) {
+static Context* context_new(sd_id128_t seed, X509 *certificate, EVP_PKEY *private_key) {
Context *context;
+ /* Note: This function takes ownership of the certificate and private_key arguments. */
+
context = new(Context, 1);
if (!context)
return NULL;
@@ -721,6 +727,8 @@ static Context* context_new(sd_id128_t seed) {
.end = UINT64_MAX,
.total = UINT64_MAX,
.seed = seed,
+ .certificate = certificate,
+ .private_key = private_key,
};
return context;
@@ -755,6 +763,9 @@ static Context* context_free(Context *context) {
else
free(context->node);
+ X509_free(context->certificate);
+ EVP_PKEY_free(context->private_key);
+
return mfree(context);
}
@@ -4979,6 +4990,8 @@ static int partition_format_verity_hash(
static int sign_verity_roothash(
const struct iovec *roothash,
+ X509 *certificate,
+ EVP_PKEY *private_key,
struct iovec *ret_signature) {
#if HAVE_OPENSSL
@@ -4989,6 +5002,7 @@ static int sign_verity_roothash(
int sigsz;
assert(roothash);
+ assert(private_key);
assert(iovec_is_set(roothash));
assert(ret_signature);
@@ -5000,7 +5014,7 @@ static int sign_verity_roothash(
if (!rb)
return log_oom();
- p7 = PKCS7_sign(arg_certificate, arg_private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
+ p7 = PKCS7_sign(certificate, private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
if (!p7)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -5039,15 +5053,13 @@ static int partition_format_verity_sig(Context *context, Partition *p) {
assert_se(hp = p->siblings[VERITY_HASH]);
assert(!hp->dropped);
- assert(arg_certificate);
-
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
- r = sign_verity_roothash(&hp->roothash, &sig);
+ r = sign_verity_roothash(&hp->roothash, context->certificate, context->private_key, &sig);
if (r < 0)
return r;
- r = x509_fingerprint(arg_certificate, fp);
+ r = x509_fingerprint(context->certificate, fp);
if (r < 0)
return log_error_errno(r, "Unable to calculate X509 certificate fingerprint: %m");
@@ -6040,60 +6052,6 @@ static int context_mkfs(Context *context) {
return 0;
}
-static int parse_x509_certificate(const char *certificate, size_t certificate_size, X509 **ret) {
-#if HAVE_OPENSSL
- _cleanup_(X509_freep) X509 *cert = NULL;
- _cleanup_(BIO_freep) BIO *cb = NULL;
-
- assert(certificate);
- assert(certificate_size > 0);
- assert(ret);
-
- cb = BIO_new_mem_buf(certificate, certificate_size);
- if (!cb)
- return log_oom();
-
- cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
- if (!cert)
- return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
-
- if (ret)
- *ret = TAKE_PTR(cert);
-
- return 0;
-#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot parse X509 certificate.");
-#endif
-}
-
-static int parse_private_key(const char *key, size_t key_size, EVP_PKEY **ret) {
-#if HAVE_OPENSSL
- _cleanup_(BIO_freep) BIO *kb = NULL;
- _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
-
- assert(key);
- assert(key_size > 0);
- assert(ret);
-
- kb = BIO_new_mem_buf(key, key_size);
- if (!kb)
- return log_oom();
-
- pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
- if (!pk)
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
-
- if (ret)
- *ret = TAKE_PTR(pk);
-
- return 0;
-#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot parse private key.");
-#endif
-}
-
static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *ret) {
struct {
sd_id128_t type_uuid;
@@ -7898,9 +7856,7 @@ static int help(void) {
return 0;
}
-static int parse_argv(int argc, char *argv[]) {
- _cleanup_free_ char *private_key = NULL;
-
+static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY **ret_private_key, OpenSSLAskPasswordUI **ret_ui) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
@@ -7989,11 +7945,17 @@ static int parse_argv(int argc, char *argv[]) {
{}
};
+ _cleanup_(X509_freep) X509 *certificate = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
bool auto_hash_pcr_values = true, auto_public_key_pcr_mask = true, auto_pcrlock = true;
int c, r;
assert(argc >= 0);
assert(argv);
+ assert(ret_certificate);
+ assert(ret_private_key);
+ assert(ret_ui);
while ((c = getopt_long(argc, argv, "hs:SCP", options, NULL)) >= 0)
@@ -8153,7 +8115,7 @@ static int parse_argv(int argc, char *argv[]) {
}
case ARG_PRIVATE_KEY: {
- r = free_and_strdup_warn(&private_key, optarg);
+ r = free_and_strdup_warn(&arg_private_key, optarg);
if (r < 0)
return r;
break;
@@ -8169,20 +8131,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CERTIFICATE: {
- _cleanup_free_ char *cert = NULL;
- size_t n = 0;
-
- r = read_full_file_full(
- AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
- READ_FULL_FILE_CONNECT_SOCKET,
- NULL,
- &cert, &n);
- if (r < 0)
- return log_error_errno(r, "Failed to read certificate file '%s': %m", optarg);
-
- X509_free(arg_certificate);
- arg_certificate = NULL;
- r = parse_x509_certificate(cert, n, &arg_certificate);
+ r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_certificate);
if (r < 0)
return r;
break;
@@ -8518,39 +8467,38 @@ static int parse_argv(int argc, char *argv[]) {
*p = gpt_partition_type_override_architecture(*p, arg_architecture);
}
- if (private_key && arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
- _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 (arg_certificate) {
+ r = openssl_load_x509_certificate(arg_certificate, &certificate);
if (r < 0)
- return log_error_errno(r, "Failed to read key file '%s': %m", private_key);
+ return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
+ }
- r = parse_private_key(k, n, &arg_private_key);
- if (r < 0)
- return r;
- } 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(
+ if (arg_private_key) {
+ if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
+ r = parse_path_argument(arg_private_key, /*suppress_root=*/ false, &arg_private_key);
+ if (r < 0)
+ return r;
+ }
+
+ r = openssl_load_private_key(
arg_private_key_source_type,
arg_private_key_source,
- private_key,
- &arg_private_key);
+ arg_private_key,
+ &(AskPasswordRequest) {
+ .id = "repart-private-key-pin",
+ .keyring = arg_private_key,
+ .credential = "repart.private-key-pin",
+ },
+ &private_key,
+ &ui);
if (r < 0)
- return log_error_errno(
- r,
- "Failed to load key '%s' from OpenSSL private key source %s: %m",
- private_key,
- arg_private_key_source);
+ return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
}
+ *ret_certificate = TAKE_PTR(certificate);
+ *ret_private_key = TAKE_PTR(private_key);
+ *ret_ui = TAKE_PTR(ui);
+
return 1;
}
@@ -8967,6 +8915,9 @@ static int determine_auto_size(Context *c) {
}
static int run(int argc, char *argv[]) {
+ _cleanup_(X509_freep) X509 *certificate = NULL;
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
_cleanup_(context_freep) Context* context = NULL;
@@ -8975,7 +8926,7 @@ static int run(int argc, char *argv[]) {
log_setup();
- r = parse_argv(argc, argv);
+ r = parse_argv(argc, argv, &certificate, &private_key, &ui);
if (r <= 0)
return r;
@@ -9034,10 +8985,13 @@ static int run(int argc, char *argv[]) {
return log_oom();
}
- context = context_new(arg_seed);
+ context = context_new(arg_seed, certificate, private_key);
if (!context)
return log_oom();
+ TAKE_PTR(certificate);
+ TAKE_PTR(private_key);
+
r = context_read_seed(context, arg_root);
if (r < 0)
return r;
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
index 2ab89c7639..818f4a5f19 100644
--- a/src/shared/openssl-util.c
+++ b/src/shared/openssl-util.c
@@ -3,12 +3,15 @@
#include <endian.h>
#include "alloc-util.h"
+#include "ask-password-api.h"
#include "fd-util.h"
+#include "fileio.h"
#include "hexdecoct.h"
#include "memory-util.h"
#include "openssl-util.h"
#include "random-util.h"
#include "string-util.h"
+#include "strv.h"
#if HAVE_OPENSSL
# include <openssl/rsa.h>
@@ -1309,10 +1312,15 @@ int pkey_generate_volume_keys(
}
}
-static int load_key_from_provider(const char *provider, const char *private_key_uri, EVP_PKEY **ret) {
+static int load_key_from_provider(
+ const char *provider,
+ const char *private_key_uri,
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret) {
assert(provider);
assert(private_key_uri);
+ assert(ui);
assert(ret);
#if OPENSSL_VERSION_MAJOR >= 3
@@ -1325,8 +1333,8 @@ static int load_key_from_provider(const char *provider, const char *private_key_
_cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
private_key_uri,
- /* ui_method= */ NULL,
- /* ui_data= */ NULL,
+ ui->method,
+ &ui->request,
/* post_process= */ NULL,
/* post_process_data= */ NULL);
if (!store)
@@ -1348,10 +1356,10 @@ static int load_key_from_provider(const char *provider, const char *private_key_
#endif
}
-static int load_key_from_engine(const char *engine, const char *private_key_uri, EVP_PKEY **ret) {
-
+static int load_key_from_engine(const char *engine, const char *private_key_uri, OpenSSLAskPasswordUI *ui, EVP_PKEY **ret) {
assert(engine);
assert(private_key_uri);
+ assert(ui);
assert(ret);
#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
@@ -1363,11 +1371,13 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
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 (ENGINE_ctrl(e, ENGINE_CTRL_SET_USER_INTERFACE, /*i=*/ 0, ui->method, /*f=*/ NULL) <= 0)
+ return log_openssl_errors("Failed to set engine user interface");
+
+ if (ENGINE_ctrl(e, ENGINE_CTRL_SET_CALLBACK_DATA, /*i=*/ 0, &ui->request, /*f=*/ NULL) <= 0)
+ return log_openssl_errors("Failed to set engine user interface data");
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(e, private_key_uri, ui->method, &ui->request);
if (!private_key)
return log_openssl_errors("Failed to load private key from '%s'", private_key_uri);
REENABLE_WARNING;
@@ -1384,24 +1394,88 @@ int openssl_load_key_from_token(
KeySourceType private_key_source_type,
const char *private_key_source,
const char *private_key,
- EVP_PKEY **ret) {
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret_private_key) {
assert(IN_SET(private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER));
assert(private_key_source);
+ assert(ui);
assert(private_key);
switch (private_key_source_type) {
case OPENSSL_KEY_SOURCE_ENGINE:
- return load_key_from_engine(private_key_source, private_key, ret);
+ return load_key_from_engine(private_key_source, private_key, ui, ret_private_key);
case OPENSSL_KEY_SOURCE_PROVIDER:
- return load_key_from_provider(private_key_source, private_key, ret);
+ return load_key_from_provider(private_key_source, private_key, ui, ret_private_key);
default:
assert_not_reached();
}
}
+
+static int openssl_ask_password_ui_read(UI *ui, UI_STRING *uis) {
+ int r;
+
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT: {
+ /* If no ask password request was configured use the default openssl UI. */
+ AskPasswordRequest *req = UI_get0_user_data(ui);
+ if (!req)
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+
+ req->message = UI_get0_output_string(uis);
+
+ _cleanup_(strv_freep) char **l = NULL;
+ r = ask_password_auto(req, /*until=*/ 0, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &l);
+ if (r < 0) {
+ log_error_errno(r, "Failed to query for PIN: %m");
+ return 0;
+ }
+
+ if (strv_length(l) != 1) {
+ log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected only a single password/pin.");
+ return 0;
+ }
+
+ if (UI_set_result(ui, uis, *l) != 0) {
+ log_openssl_errors("Failed to set user interface result");
+ return 0;
+ }
+
+ return 1;
+ }
+ default:
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+ }
+}
#endif
+int openssl_ask_password_ui_new(OpenSSLAskPasswordUI **ret) {
+#if HAVE_OPENSSL
+ assert(ret);
+
+ _cleanup_(UI_destroy_methodp) UI_METHOD *method = UI_create_method("systemd-ask-password");
+ if (!method)
+ return log_openssl_errors("Failed to initialize openssl user interface");
+
+ if (UI_method_set_reader(method, openssl_ask_password_ui_read) != 0)
+ return log_openssl_errors("Failed to set openssl user interface reader");
+
+ OpenSSLAskPasswordUI *ui = new(OpenSSLAskPasswordUI, 1);
+ if (!ui)
+ return log_oom_debug();
+
+ *ui = (OpenSSLAskPasswordUI) {
+ .method = TAKE_PTR(method),
+ };
+
+ *ret = TAKE_PTR(ui);
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot create ask-password user interface.");
+#endif
+}
+
int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
#if HAVE_OPENSSL
_cleanup_free_ uint8_t *der = NULL;
@@ -1420,6 +1494,126 @@ int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
#endif
}
+int openssl_load_x509_certificate(const char *path, X509 **ret) {
+#if HAVE_OPENSSL
+ _cleanup_free_ char *rawcert = NULL;
+ _cleanup_(X509_freep) X509 *cert = NULL;
+ _cleanup_(BIO_freep) BIO *cb = NULL;
+ size_t rawcertsz;
+ int r;
+
+ assert(path);
+ assert(ret);
+
+ r = read_full_file_full(
+ AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
+ READ_FULL_FILE_CONNECT_SOCKET,
+ NULL,
+ &rawcert, &rawcertsz);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
+
+ cb = BIO_new_mem_buf(rawcert, rawcertsz);
+ if (!cb)
+ return log_oom_debug();
+
+ cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
+ if (!cert)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ if (ret)
+ *ret = TAKE_PTR(cert);
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load X509 certificate.");
+#endif
+}
+
+static int openssl_load_private_key_from_file(const char *path, EVP_PKEY **ret) {
+#if HAVE_OPENSSL
+ _cleanup_(erase_and_freep) char *rawkey = NULL;
+ _cleanup_(BIO_freep) BIO *kb = NULL;
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
+ size_t rawkeysz;
+ int r;
+
+ assert(path);
+ assert(ret);
+
+ r = read_full_file_full(
+ AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
+ READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+ NULL,
+ &rawkey, &rawkeysz);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to read key file '%s': %m", path);
+
+ kb = BIO_new_mem_buf(rawkey, rawkeysz);
+ if (!kb)
+ return log_oom_debug();
+
+ pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
+ if (!pk)
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+
+ if (ret)
+ *ret = TAKE_PTR(pk);
+
+ return 0;
+#else
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load private key.");
+#endif
+}
+
+int openssl_load_private_key(
+ KeySourceType private_key_source_type,
+ const char *private_key_source,
+ const char *private_key,
+ const AskPasswordRequest *request,
+ EVP_PKEY **ret_private_key,
+ OpenSSLAskPasswordUI **ret_user_interface) {
+
+ int r;
+
+ assert(private_key);
+ assert(request);
+
+ if (private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
+ r = openssl_load_private_key_from_file(private_key, ret_private_key);
+ if (r < 0)
+ return r;
+
+ *ret_user_interface = NULL;
+ } else {
+ _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+ r = openssl_ask_password_ui_new(&ui);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to allocate ask-password user interface: %m");
+
+ ui->request = *request;
+
+ r = openssl_load_key_from_token(
+ private_key_source_type,
+ private_key_source,
+ private_key,
+ ui,
+ ret_private_key);
+ if (r < 0)
+ return log_debug_errno(
+ r,
+ "Failed to load key '%s' from OpenSSL private key source %s: %m",
+ private_key,
+ private_key_source);
+
+ *ret_user_interface = TAKE_PTR(ui);
+ }
+
+ return 0;
+}
+
int parse_openssl_key_source_argument(
const char *argument,
char **private_key_source,
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
index 1a89fcc2bd..c9acd40f22 100644
--- a/src/shared/openssl-util.h
+++ b/src/shared/openssl-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "ask-password-api.h"
#include "iovec-util.h"
#include "macro.h"
#include "sha256.h"
@@ -13,6 +14,8 @@ typedef enum KeySourceType {
_OPENSSL_KEY_SOURCE_INVALID = -EINVAL,
} KeySourceType;
+typedef struct OpenSSLAskPasswordUI OpenSSLAskPasswordUI;
+
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
@@ -26,6 +29,7 @@ int parse_openssl_key_source_argument(const char *argument, char **private_key_s
# include <openssl/opensslv.h>
# include <openssl/pkcs7.h>
# include <openssl/ssl.h>
+# include <openssl/ui.h>
# include <openssl/x509v3.h>
# ifndef OPENSSL_VERSION_MAJOR
/* OPENSSL_VERSION_MAJOR macro was added in OpenSSL 3. Thus, if it doesn't exist, we must be before OpenSSL 3. */
@@ -130,12 +134,13 @@ 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(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, EVP_PKEY **ret);
+int openssl_load_key_from_token(KeySourceType private_key_source_type, const char *private_key_source, const char *private_key, OpenSSLAskPasswordUI *ui, EVP_PKEY **ret_private_key);
#else
typedef struct X509 X509;
typedef struct EVP_PKEY EVP_PKEY;
+typedef struct UI_METHOD UI_METHOD;
static inline void *X509_free(X509 *p) {
assert(p == NULL);
@@ -147,11 +152,17 @@ static inline void *EVP_PKEY_free(EVP_PKEY *p) {
return NULL;
}
+static inline void* UI_destroy_method(UI_METHOD *p) {
+ assert(p == NULL);
+ return NULL;
+}
+
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) {
+ OpenSSLAskPasswordUI *ui,
+ EVP_PKEY **ret_private_key) {
return -EOPNOTSUPP;
}
@@ -160,9 +171,37 @@ static inline int openssl_load_key_from_token(
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY*, EVP_PKEY_free, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UI_METHOD*, UI_destroy_method, NULL);
+
+struct OpenSSLAskPasswordUI {
+ AskPasswordRequest request;
+ UI_METHOD *method;
+};
+
+int openssl_ask_password_ui_new(OpenSSLAskPasswordUI **ret);
+
+static inline OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
+ if (!ui)
+ return NULL;
+
+ UI_destroy_method(ui->method);
+ return mfree(ui);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OpenSSLAskPasswordUI*, openssl_ask_password_ui_free, NULL);
int x509_fingerprint(X509 *cert, uint8_t buffer[static X509_FINGERPRINT_SIZE]);
+int openssl_load_x509_certificate(const char *path, X509 **ret);
+
+int openssl_load_private_key(
+ KeySourceType private_key_source_type,
+ const char *private_key_source,
+ const char *private_key,
+ const AskPasswordRequest *request,
+ EVP_PKEY **ret_private_key,
+ OpenSSLAskPasswordUI **ret_user_interface);
+
#if PREFER_OPENSSL
/* The openssl definition */
typedef const EVP_MD* hash_md_t;