From 78ec287ad4d0ecc7f937d878998d22d6ea0256ec Mon Sep 17 00:00:00 2001
From: David Seifert <soap@gentoo.org>
Date: Sun, 25 Oct 2026 11:24:32 +0100
Subject: [PATCH] sbsign, sbvarsign: replace ENGINE key loading with OpenSSL
 providers

The ENGINE API is deprecated since OpenSSL 3.0 and removed in OpenSSL 4,
so sbsigntools no longer builds against it.

Replace fileio_read_engine_key() with fileio_read_provider_key(), which
loads the "default" provider plus the requested one and reads the
private key through OSSL_STORE, prompting for a pass phrase via the
existing UI method.

The --engine/-e option of sbsign and sbvarsign becomes --provider/-p.
The key argument is now an OSSL_STORE URI, e.g.

  sbsign --provider pkcs11 --key 'pkcs11:token=foo;object=bar' ...

Signed-off-by: David Seifert <soap@gentoo.org>
---
 src/fileio.c    | 52 ++++++++++++++++++++++++++++++++++---------------
 src/fileio.h    |  2 +-
 src/sbsign.c    | 18 ++++++++---------
 src/sbvarsign.c | 18 ++++++++---------
 4 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 032eb1e..35fbbb3 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -39,7 +39,9 @@
 #include <openssl/bio.h>
 #include <openssl/pem.h>
 #include <openssl/err.h>
-#include <openssl/engine.h>
+#include <openssl/provider.h>
+#include <openssl/store.h>
+#include <openssl/ui.h>
 
 #include <ccan/talloc/talloc.h>
 #include <ccan/read_write_all/read_write_all.h>
@@ -55,22 +57,23 @@ static int ui_read(UI *ui, UI_STRING *uis)
 	if (UI_get_string_type(uis) != UIT_PROMPT)
 		return 0;
 
-	EVP_read_pw_string(password, sizeof(password), "Enter engine key pass phrase:", 0);
+	EVP_read_pw_string(password, sizeof(password), "Enter key pass phrase:", 0);
 	UI_set_result(ui, uis, password);
 	return 1;
 }
 
-EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename)
+EVP_PKEY *fileio_read_provider_key(const char *provider, const char *uri)
 {
-	UI_METHOD *ui;
-	ENGINE *e;
+	UI_METHOD *ui = NULL;
+	OSSL_STORE_CTX *store = NULL;
+	OSSL_STORE_INFO *info;
 	EVP_PKEY *pkey = NULL;
 
-	ENGINE_load_builtin_engines();
-	e = ENGINE_by_id(engine);
-
-	if (!e) {
-		fprintf(stderr, "Failed to load engine: %s\n", engine);
+	/* explicitly loading any provider disables the implicit default
+	 * provider, which we still need for digests and PKCS#7 */
+	if (!OSSL_PROVIDER_load(NULL, "default") ||
+	    !OSSL_PROVIDER_load(NULL, provider)) {
+		fprintf(stderr, "Failed to load provider: %s\n", provider);
 		ERR_print_errors_fp(stderr);
 		return NULL;
 	}
@@ -79,21 +82,38 @@ EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename)
 	if (!ui) {
 		fprintf(stderr, "Failed to create UI method\n");
 		ERR_print_errors_fp(stderr);
-		goto out_free;
+		return NULL;
 	}
 	UI_method_set_reader(ui, ui_read);
 
-	if (!ENGINE_init(e)) {
-		fprintf(stderr, "Failed to initialize engine %s\n", engine);
+	store = OSSL_STORE_open(uri, ui, NULL, NULL, NULL);
+	if (!store) {
+		fprintf(stderr, "Failed to open key store: %s\n", uri);
 		ERR_print_errors_fp(stderr);
 		goto out_free;
 	}
+	OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY);
+
+	while (!pkey && !OSSL_STORE_eof(store)) {
+		info = OSSL_STORE_load(store);
+		if (!info) {
+			if (OSSL_STORE_error(store))
+				break;
+			continue;
+		}
+		if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY)
+			pkey = OSSL_STORE_INFO_get1_PKEY(info);
+		OSSL_STORE_INFO_free(info);
+	}
 
-	pkey = ENGINE_load_private_key(e, filename, ui, NULL);
-	ENGINE_finish(e);
+	if (!pkey) {
+		fprintf(stderr, "Can't load key from '%s'\n", uri);
+		ERR_print_errors_fp(stderr);
+	}
 
  out_free:
-	ENGINE_free(e);
+	OSSL_STORE_close(store);
+	UI_destroy_method(ui);
 	return pkey;
 }
 
diff --git a/src/fileio.h b/src/fileio.h
index b3ed22c..2688d50 100644
--- a/src/fileio.h
+++ b/src/fileio.h
@@ -38,7 +38,7 @@
 #include <openssl/x509.h>
 
 EVP_PKEY *fileio_read_pkey(const char *filename);
-EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename);
+EVP_PKEY *fileio_read_provider_key(const char *provider, const char *uri);
 X509 *fileio_read_cert(const char *filename);
 
 int fileio_read_file(void *ctx, const char *filename,
diff --git a/src/sbsign.c b/src/sbsign.c
index 898fe66..dad58f1 100644
--- a/src/sbsign.c
+++ b/src/sbsign.c
@@ -76,7 +76,7 @@ static struct option options[] = {
 	{ "verbose", no_argument, NULL, 'v' },
 	{ "help", no_argument, NULL, 'h' },
 	{ "version", no_argument, NULL, 'V' },
-	{ "engine", required_argument, NULL, 'e'},
+	{ "provider", required_argument, NULL, 'p'},
 	{ "addcert", required_argument, NULL, 'a'},
 	{ NULL, 0, NULL, 0 },
 };
@@ -87,7 +87,7 @@ static void usage(void)
 			"<efi-boot-image>\n"
 		"Sign an EFI boot image for use with secure boot.\n\n"
 		"Options:\n"
-		"\t--engine <eng>     use the specified engine to load the key\n"
+		"\t--provider <prov>  use the specified provider to load the key\n"
 		"\t--key <keyfile>    signing key (PEM-encoded RSA "
 						"private key)\n"
 		"\t--cert <certfile>  certificate (x509 certificate)\n"
@@ -152,7 +152,7 @@ static int add_intermediate_certs(PKCS7 *p7, const char *filename)
 
 int main(int argc, char **argv)
 {
-	const char *keyfilename, *certfilename, *addcertfilename, *engine;
+	const char *keyfilename, *certfilename, *addcertfilename, *provider;
 	struct sign_context *ctx;
 	uint8_t *buf, *tmp;
 	int rc, c, sigsize;
@@ -163,11 +163,11 @@ int main(int argc, char **argv)
 	keyfilename = NULL;
 	certfilename = NULL;
 	addcertfilename = NULL;
-	engine = NULL;
+	provider = NULL;
 
 	for (;;) {
 		int idx;
-		c = getopt_long(argc, argv, "o:c:k:dvVhe:a:", options, &idx);
+		c = getopt_long(argc, argv, "o:c:k:dvVhp:a:", options, &idx);
 		if (c == -1)
 			break;
 
@@ -193,8 +193,8 @@ int main(int argc, char **argv)
 		case 'h':
 			usage();
 			return EXIT_SUCCESS;
-		case 'e':
-			engine = optarg;
+		case 'p':
+			provider = optarg;
 			break;
 		case 'a':
 			addcertfilename = optarg;
@@ -244,8 +244,8 @@ int main(int argc, char **argv)
 	 * module isn't present).  In either case ignore the errors
 	 * (malloc will cause other failures out lower down */
 	ERR_clear_error();
-	if (engine)
-		pkey = fileio_read_engine_key(engine, keyfilename);
+	if (provider)
+		pkey = fileio_read_provider_key(provider, keyfilename);
 	else
 		pkey = fileio_read_pkey(keyfilename);
 	if (!pkey)
diff --git a/src/sbvarsign.c b/src/sbvarsign.c
index 58031ec..9f2db11 100644
--- a/src/sbvarsign.c
+++ b/src/sbvarsign.c
@@ -397,7 +397,7 @@ static struct option options[] = {
 	{ "verbose", no_argument, NULL, 'v' },
 	{ "help", no_argument, NULL, 'h' },
 	{ "version", no_argument, NULL, 'V' },
-	{ "engine", required_argument, NULL, 'e'},
+	{ "provider", required_argument, NULL, 'p'},
 	{ NULL, 0, NULL, 0 },
 };
 
@@ -409,7 +409,7 @@ void usage(void)
 			"<var-name> <var-data-file>\n"
 		"Sign a blob of data for use in SetVariable().\n\n"
 		"Options:\n"
-		"\t--engine <eng>     use the specified engine to load the key\n"
+		"\t--provider <prov>  use the specified provider to load the key\n"
 		"\t--key <keyfile>    signing key (PEM-encoded RSA "
 						"private key)\n"
 		"\t--cert <certfile>  certificate (x509 certificate)\n"
@@ -438,7 +438,7 @@ static void version(void)
 
 int main(int argc, char **argv)
 {
-	const char *guid_str, *attr_str, *varname, *engine;
+	const char *guid_str, *attr_str, *varname, *provider;
 	const char *keyfilename, *certfilename;
 	struct varsign_context *ctx;
 	bool include_attrs;
@@ -448,14 +448,14 @@ int main(int argc, char **argv)
 
 	keyfilename = NULL;
 	certfilename = NULL;
-	engine = NULL;
+	provider = NULL;
 	guid_str = NULL;
 	attr_str= NULL;
 	include_attrs = false;
 
 	for (;;) {
 		int idx;
-		c = getopt_long(argc, argv, "o:g:a:k:c:ivVhe:", options, &idx);
+		c = getopt_long(argc, argv, "o:g:a:k:c:ivVhp:", options, &idx);
 		if (c == -1)
 			break;
 
@@ -487,8 +487,8 @@ int main(int argc, char **argv)
 		case 'h':
 			usage();
 			return EXIT_SUCCESS;
-		case 'e':
-			engine = optarg;
+		case 'p':
+			provider = optarg;
 			break;
 		}
 	}
@@ -551,8 +551,8 @@ int main(int argc, char **argv)
 	if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len))
 		return EXIT_FAILURE;
 
-	if (engine)
-		ctx->key = fileio_read_engine_key(engine, keyfilename);
+	if (provider)
+		ctx->key = fileio_read_provider_key(provider, keyfilename);
 	else
 		ctx->key = fileio_read_pkey(keyfilename);
 	if (!ctx->key)
