summaryrefslogtreecommitdiffstats
path: root/src/shared/openssl-util.h
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2024-10-30 15:47:58 +0100
committerDaan De Meyer <daan.j.demeyer@gmail.com>2024-11-03 10:46:14 +0100
commiteac5336c27e2c8a0024fedcde87f9bb26dec49aa (patch)
treed6d75e396d6dcb1000f5a053f775bd96eacb9107 /src/shared/openssl-util.h
parentefivars: Remove STRINGIFY() helper macros (diff)
downloadsystemd-eac5336c27e2c8a0024fedcde87f9bb26dec49aa.tar.xz
systemd-eac5336c27e2c8a0024fedcde87f9bb26dec49aa.zip
openssl-util: Query engine/provider pin via ask-password
In mkosi, we want to support signing via a hardware token. We already support this in systemd-repart and systemd-measure. However, if the hardware token is protected by a pin, the pin is asked as many as 20 times when building an image as the pin is not cached and thus requested again for every operation. Let's introduce a custom openssl ui when we use engines and providers and plug systemd-ask-password into the process. With systemd-ask-password, the pin can be cached in the kernel keyring, allowing us to reuse it without querying the user again every time to enter the pin. We use the private key URI as the keyring identifier so that the cached pin can be shared across multiple tools. Note that if the private key is pin protected, openssl will prompt both when loading the private key using the pkcs11 engine and when actually signing the roothash. To make sure our custom UI is used when signing the roothash, we have to also configure it with ENGINE_ctrl() which takes a non-owning pointer to the UI_METHOD object and its userdata object which we have to keep alive so we introduce a new AskPasswordUserInterface struct which we use to keep both objects alive together with the EVP_PKEY object. Because the AskPasswordRequest struct stores non-owning pointers to its fields, we change repart to store the private key URI as a global variable again instead of the EVP_PKEY object so that we can use the private key argument as the keyring field of the AskPasswordRequest instance without running into lifetime issues.
Diffstat (limited to '')
-rw-r--r--src/shared/openssl-util.h43
1 files changed, 41 insertions, 2 deletions
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;