From 9c6deb5733306025947a1d438a2dd4d44413a58b Mon Sep 17 00:00:00 2001
From: David Seifert <soap@gentoo.org>
Date: Sun, 25 Oct 2026 14:28:29 +0100
Subject: [PATCH] sign-efi-sig-list, efi-updatevar: replace ENGINE key loading
 with OpenSSL providers

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

Make read_private_key() load the "default" provider plus the requested
one and read the private key through OSSL_STORE, prompting for a pass
phrase or PIN via a UI method.

The -e <engine> option of sign-efi-sig-list becomes -p <provider>, and
the --engine option of efi-updatevar becomes --provider.  The key
argument is now an OSSL_STORE URI, e.g.

  sign-efi-sig-list -p pkcs11 -k 'pkcs11:token=foo;object=bar' ...
---
 efi-updatevar.c        | 10 +++----
 include/openssl_sign.h |  4 +--
 lib/openssl_sign.c     | 59 ++++++++++++++++++++++++++----------------
 sign-efi-sig-list.c    | 12 ++++-----
 4 files changed, 50 insertions(+), 35 deletions(-)

diff --git a/efi-updatevar.c b/efi-updatevar.c
index 4247105..374a182 100644
--- a/efi-updatevar.c
+++ b/efi-updatevar.c
@@ -52,7 +52,7 @@ help(const char *progname)
 	       "\t-g <guid>\tOptional <guid> for the X509 Certificate\n"
 	       "\t-k <key>\tSecret key file for authorising User Mode updates\n"
 	       "\t-d <list>[-<entry>]\tDelete the signature list <list> (or just a single <entry> within the list)\n"
-	       "\t--engine <eng>\tUse engine <eng> for private key\n"
+	       "\t--provider <prov>\tUse provider <prov> for private key\n"
 	       );
 }
 
@@ -61,7 +61,7 @@ main(int argc, char *argv[])
 {
 	char *variables[] = { "PK", "KEK", "db", "dbx" };
 	char *signedby[] = { "PK", "PK", "KEK", "KEK" };
-	char *engine = NULL;
+	char *provider = NULL;
 	EFI_GUID *owners[] = { &GV_GUID, &GV_GUID, &SIG_DB, &SIG_DB };
 	EFI_GUID *owner, guid = MOK_OWNER;
 	int i, esl_mode = 0, fd, ret, delsig = -1, delentry = -1;
@@ -116,8 +116,8 @@ main(int argc, char *argv[])
 			sscanf(argv[2], "%d-%d", &delsig, &delentry);
 			argv += 2;
 			argc -= 2;
-		} else if (strcmp(argv[1], "--engine") == 0) {
-			engine = argv[2];
+		} else if (strcmp(argv[1], "--provider") == 0) {
+			provider = argv[2];
 			argv += 2;
 			argc -= 2;
 		} else {
@@ -286,7 +286,7 @@ main(int argc, char *argv[])
 			fprintf(stderr, "Can't update variable%s without a key\n", variable_is_setupmode() ? "" : " in User Mode");
 			exit(1);
 		}
-		EVP_PKEY *pkey = read_private_key(engine, key_file);
+		EVP_PKEY *pkey = read_private_key(provider, key_file);
 		if (!pkey) {
 			fprintf(stderr, "error reading private key %s\n", key_file);
 			exit(1);
diff --git a/include/openssl_sign.h b/include/openssl_sign.h
index 136ad75..18f8be6 100644
--- a/include/openssl_sign.h
+++ b/include/openssl_sign.h
@@ -2,9 +2,9 @@
 
 int
 sign_efi_var(char *payload, int payload_size, char *keyfile, char *certfile,
-	     unsigned char **sig, int *sigsize, char *engine);
+	     unsigned char **sig, int *sigsize, char *provider);
 int
 sign_efi_var_ssl(char *payload, int payload_size, EVP_PKEY *pkey, X509 *cert,
 		 unsigned char **sig, int *sigsize);
 EVP_PKEY *
-read_private_key(char *engine, char *keyfile);
+read_private_key(char *provider, char *keyfile);
diff --git a/lib/openssl_sign.c b/lib/openssl_sign.c
index 714ce1a..be02fc6 100644
--- a/lib/openssl_sign.c
+++ b/lib/openssl_sign.c
@@ -7,7 +7,9 @@
 #include <openssl/pem.h>
 #include <openssl/err.h>
 #include <openssl/sha.h>
-#include <openssl/engine.h>
+#include <openssl/provider.h>
+#include <openssl/store.h>
+#include <openssl/ui.h>
 
 #include <openssl_sign.h>
 
@@ -33,7 +35,7 @@ sign_efi_var_ssl(char *payload, int payload_size, EVP_PKEY *pkey, X509 *cert,
 
 int
 sign_efi_var(char *payload, int payload_size, char *keyfile, char *certfile,
-	     unsigned char **sig, int *sigsize, char *engine)
+	     unsigned char **sig, int *sigsize, char *provider)
 {
 	int ret;
 
@@ -60,7 +62,7 @@ sign_efi_var(char *payload, int payload_size, char *keyfile, char *certfile,
 		return 1;
 	}
 
-	EVP_PKEY *pkey = read_private_key(engine, keyfile);
+	EVP_PKEY *pkey = read_private_key(provider, keyfile);
 	if (!pkey) {
 		ERR_print_errors_fp(stdout);
 		fprintf(stderr, "error reading private key %s\n", keyfile);
@@ -103,54 +105,67 @@ 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;
 }
 
 static EVP_PKEY *
-read_engine_private_key(char *engine, char *keyfile)
+read_provider_private_key(char *provider, char *uri)
 {
 	UI_METHOD *ui;
-	ENGINE *e;
+	OSSL_STORE_CTX *store;
+	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;
 	}
 
-	ui = UI_create_method("sbsigntools");
+	ui = UI_create_method("efitools");
 	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;
 	}
-
-	pkey = ENGINE_load_private_key(e, keyfile, ui, NULL);
-	ENGINE_finish(e);
+	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);
+	}
+	OSSL_STORE_close(store);
 
  out_free:
-	ENGINE_free(e);
+	UI_destroy_method(ui);
 	return pkey;
 }
 
 EVP_PKEY *
-read_private_key(char *engine, char *keyfile)
+read_private_key(char *provider, char *keyfile)
 {
-	if (engine)
-		return read_engine_private_key(engine, keyfile);
+	if (provider)
+		return read_provider_private_key(provider, keyfile);
 	else
 		return read_pem_private_key(keyfile);
 }
diff --git a/sign-efi-sig-list.c b/sign-efi-sig-list.c
index 94bd7d4..8869b6a 100644
--- a/sign-efi-sig-list.c
+++ b/sign-efi-sig-list.c
@@ -31,7 +31,7 @@
 static void
 usage(const char *progname)
 {
-	printf("Usage: %s [-r] [-m] [-a] [-g <guid>] [-o] [-t <timestamp>] [-i <infile>] [-c <crt file>] [-k <key file>] [-e <engine>] <var> <efi sig list file> <output file>\n", progname);
+	printf("Usage: %s [-r] [-m] [-a] [-g <guid>] [-o] [-t <timestamp>] [-i <infile>] [-c <crt file>] [-k <key file>] [-p <provider>] <var> <efi sig list file> <output file>\n", progname);
 }
 
 static void
@@ -56,7 +56,7 @@ help(const char *progname)
 	       "\t-g <guid>        Use <guid> as the signature owner GUID\n"
 	       "\t-c <crt>         <crt> is the file containing the signing certificate in PEM format\n"
 	       "\t-k <key>         <key> is the file containing the key for <crt> in PEM format\n"
-	       "\t-e <engine>      Use openssl engine <engine> for the private key\n"
+	       "\t-p <provider>    Use openssl provider <provider> for the private key\n"
 	       );
 }
 
@@ -67,7 +67,7 @@ main(int argc, char *argv[])
 		*str, *signedinput = NULL, *timestampstr = NULL;
 	void *out;
 	const char *progname = argv[0];
-	char *engine = NULL;
+	char *provider = NULL;
 	unsigned char *sigbuf;
 	int rsasig = 0, monotonic = 0, varlen, i, outputforsign = 0, outlen,
 		sigsize;
@@ -126,8 +126,8 @@ main(int argc, char *argv[])
 			certfile = argv[2];
 			argv += 2;
 			argc -= 2;
-		} else if (strcmp("-e", argv[1]) == 0) {
-			engine = argv[2];
+		} else if (strcmp("-p", argv[1]) == 0) {
+			provider = argv[2];
 			argv += 2;
 			argc -= 2;
 		} else  {
@@ -249,7 +249,7 @@ main(int argc, char *argv[])
 			exit(1);
 		}
 		if (sign_efi_var(signbuf, signbuflen, keyfile, certfile,
-				 &sigbuf, &sigsize, engine))
+				 &sigbuf, &sigsize, provider))
 			exit(1);
 	}
 	printf("Signature of size %d\n", sigsize);
