U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9] tools: mkeficapsule: Rework pkcs11 support
@ 2026-07-21 14:13 Fabio Estevam via U-Boot
  2026-07-21 15:16 ` Quentin Schulz via U-Boot
  0 siblings, 1 reply; 2+ messages in thread
From: Fabio Estevam via U-Boot @ 2026-07-21 14:13 UTC (permalink / raw)
  To: xypron.glpk
  Cc: trini, ilias.apalodimas, sjg, quentin.schulz, marex, dwmw2,
	Wojciech.Dubowik, fra.schnyder, u-boot, Fabio Estevam

From: Wojciech Dubowik <Wojciech.Dubowik@mt.com>

Some distributions, such as OpenEmbedded, build GnuTLS without
PKCS #11 support, which causes mkeficapsule to fail at link time.

Detect whether GnuTLS was built with p11-kit support and enable
PKCS #11 functionality only when available. Emit a build warning
when mkeficapsule is built without this functionality.

When PKCS #11 is available, rely on GnuTLS and p11-kit for automatic
provider discovery, allowing PKCS #11 URIs to be used without the
PKCS11_MODULE_PATH environment variable.

Document the use of PKCS #11 URIs for private keys and certificates.

Suggested-by: Tom Rini <trini@konsulko.com>
Cc: Franz Schnyder <fra.schnyder@gmail.com>
Signed-off-by: Wojciech Dubowik <Wojciech.Dubowik@mt.com>
Signed-off-by: Fabio Estevam <festevam@gmail.com>
---
Sorry for the resend. I forgot to CC the list.

Only built-tested.

Changes since v8:
- Removed Quentin's and Simon's review tags due to the significant changes
  introduced in this version.
- Warn when mkeficapsule is built without PKCS#11 support.
- Rely on GnuTLS and p11-kit for automatic PKCS#11 provider discovery,
  removing PKCS11_MODULE_PATH and manual initialization/deinitialization.
- Improve user-facing errors for PKCS#11 certificate and key imports.
- Document the use of PKCS#11 URIs in mkeficapsule.1 and the UEFI
  documentation.
- Remove PKCS11_MODULE_PATH from the SoftHSM test to verify automatic
  provider discovery through GnuTLS and p11-kit.

 doc/develop/uefi/uefi.rst | 13 ++++++
 doc/mkeficapsule.1        | 25 ++++++++--
 tools/Makefile            |  9 ++++
 tools/binman/ftest.py     |  3 +-
 tools/mkeficapsule.c      | 98 +++++++++++++++++++++++----------------
 5 files changed, 102 insertions(+), 46 deletions(-)

diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst
index 3ca22b572a92..cf7f638f2c23 100644
--- a/doc/develop/uefi/uefi.rst
+++ b/doc/develop/uefi/uefi.rst
@@ -597,6 +597,19 @@ and used by the steps highlighted below.
       [--fit | --raw | --guid <guid-string] \
       <image_blob> <capsule_file_name>
 
+If ``mkeficapsule`` was built with PKCS #11 support, the private key and
+certificate arguments can instead be PKCS #11 URIs. GnuTLS automatically
+discovers PKCS #11 providers configured through p11-kit. For example:
+
+.. code-block:: console
+
+    $ mkeficapsule --monotonic-count 1 \
+      --private-key 'pkcs11:token=U-Boot;object=capsule-key;type=private' \
+      --certificate 'pkcs11:token=U-Boot;object=capsule-cert;type=cert' \
+      --index 1 --instance 0 \
+      [--fit | --raw | --guid <guid-string] \
+      <image_blob> <capsule_file_name>
+
 Anti-rollback Protection
 ************************
 
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
index ed296730eeb9..dfa9b805ca32 100644
--- a/doc/mkeficapsule.1
+++ b/doc/mkeficapsule.1
@@ -108,12 +108,12 @@ With signing,
 are all mandatory.
 
 .TP
-.BI "-p\fR,\fB --private-key " private-key-file
-Specify signer's private key file in PEM
+.BI "-p\fR,\fB --private-key " private-key-file-or-URI
+Specify the signer's private key as a PEM file or PKCS #11 URI.
 
 .TP
-.BI "-c\fR,\fB --certificate " certificate-file
-Specify signer's certificate file in EFI certificate list format
+.BI "-c\fR,\fB --certificate " certificate-file-or-URI
+Specify the signer's certificate as a PEM file or PKCS #11 URI.
 
 .TP
 .BI "-m\fR,\fB --monotonic-count " count
@@ -124,6 +124,23 @@ at every firmware update.
 .B "-d\fR,\fB --dump-sig"
 Dump signature data into <capsule-file-name>.p7 file
 
+.SH "PKCS #11"
+If
+.B mkeficapsule
+was built with PKCS #11 support, a PKCS #11 URI can be used in place of the
+private key or certificate filename. PKCS #11 providers configured through
+p11-kit are discovered automatically by GnuTLS.
+
+For example:
+
+.EX
+mkeficapsule --monotonic-count 1 \\
+  --private-key 'pkcs11:token=U-Boot;object=capsule-key;type=private' \\
+  --certificate 'pkcs11:token=U-Boot;object=capsule-cert;type=cert' \\
+  --index 1 --instance 0 --guid <guid-string> \\
+  <image-blob> <capsule-file>
+.EE
+
 .SH "GUIDGEN OPTIONS"
 
 .TP
diff --git a/tools/Makefile b/tools/Makefile
index 1a5f425ecdaa..c156af9fc5e9 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -271,6 +271,15 @@ mkeficapsule-objs := generated/lib/uuid.o \
 	$(LIBFDT_OBJS) \
 	mkeficapsule.o
 hostprogs-always-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
+ifeq ($(CONFIG_TOOLS_MKEFICAPSULE),y)
+GNUTLS_SUPPORTS_P11KIT = $(shell pkg-config --libs gnutls --print-requires-private \
+			 2> /dev/null | grep p11-kit-1)
+ifeq ($(GNUTLS_SUPPORTS_P11KIT),p11-kit-1)
+HOSTCFLAGS_mkeficapsule.o += -DMKEFICAPSULE_PKCS11
+else
+$(warning Building mkeficapsule without PKCS#11 support)
+endif
+endif
 
 include tools/fwumdata_src/fwumdata.mk
 
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index bf98b268ac15..d8f4d4ab2439 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -7588,8 +7588,7 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
         self.assertIsNotNone(softhsm2_lib)
 
         with unittest.mock.patch.dict('os.environ',
-                                      {'SOFTHSM2_CONF': softhsm2_conf,
-                                       'PKCS11_MODULE_PATH': softhsm2_lib}):
+                                      {'SOFTHSM2_CONF': softhsm2_conf}):
                 softhsm2_util.run_cmd('--init-token', '--free', '--label',
                                       'U-Boot token', '--pin', '1111',
                                       '--so-pin', '222222')
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index ec640c57e8a5..b81c295f91e5 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -81,8 +81,8 @@ static void print_usage_mkeficapsule(void)
 		"\t-i, --index <index>         update image index\n"
 		"\t-I, --instance <instance>   update hardware instance\n"
 		"\t-v, --fw-version <version>  firmware version\n"
-		"\t-p, --private-key <privkey file>  private key file\n"
-		"\t-c, --certificate <cert file>     signer's certificate file\n"
+		"\t-p, --private-key <file|URI>  private key file or PKCS#11 URI\n"
+		"\t-c, --certificate <file|URI>  certificate file or PKCS#11 URI\n"
 		"\t-m, --monotonic-count <count>     monotonic count\n"
 		"\t-d, --dump-sig              dump signature to <output file>.p7\n"
 		"\t-A, --fw-accept  firmware accept capsule, requires GUID, no image blob\n"
@@ -207,6 +207,58 @@ static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg)
 	return 0;
 }
 
+#ifdef MKEFICAPSULE_PKCS11
+static int import_pkcs11_crt(gnutls_x509_crt_t *x509, struct auth_context *ctx)
+{
+	gnutls_pkcs11_obj_t *obj_list;
+	unsigned int obj_list_size = 0;
+	int ret;
+
+	ret = gnutls_pkcs11_obj_list_import_url4(&obj_list, &obj_list_size,
+						 ctx->cert_file, 0);
+	if (ret < 0) {
+		fprintf(stderr, "Failed to import PKCS#11 certificate: %s\n",
+			gnutls_strerror(ret));
+		return ret;
+	}
+	if (!obj_list_size) {
+		fprintf(stderr,
+			"Failed to import PKCS#11 certificate: no matching object\n");
+		return -1;
+	}
+
+	gnutls_x509_crt_import_pkcs11(*x509, obj_list[0]);
+
+	return 0;
+}
+
+static int import_pkcs11_key(gnutls_privkey_t *pkey, struct auth_context *ctx)
+{
+	int ret;
+
+	ret = gnutls_privkey_import_pkcs11_url(*pkey, ctx->key_file);
+	if (ret < 0)
+		fprintf(stderr, "Failed to import PKCS#11 private key: %s\n",
+			gnutls_strerror(ret));
+
+	return ret;
+}
+#else
+static int import_pkcs11_crt(gnutls_x509_crt_t *x509, struct auth_context *ctx)
+{
+	fprintf(stderr,
+		"Cannot import PKCS#11 certificate: support is disabled\n");
+	return -1;
+}
+
+static int import_pkcs11_key(gnutls_privkey_t *pkey, struct auth_context *ctx)
+{
+	fprintf(stderr,
+		"Cannot import PKCS#11 private key: support is disabled\n");
+	return -1;
+}
+#endif
+
 /**
  * create_auth_data - compose authentication data in capsule
  * @auth_context:	Pointer to authentication context
@@ -229,9 +281,6 @@ static int create_auth_data(struct auth_context *ctx)
 	gnutls_pkcs7_t pkcs7;
 	gnutls_datum_t data;
 	gnutls_datum_t signature;
-	gnutls_pkcs11_obj_t *obj_list;
-	unsigned int obj_list_size = 0;
-	const char *lib;
 	int ret;
 	bool pkcs11_cert = false;
 	bool pkcs11_key = false;
@@ -242,24 +291,6 @@ static int create_auth_data(struct auth_context *ctx)
 	if (!strncmp(ctx->key_file, "pkcs11:", strlen("pkcs11:")))
 		pkcs11_key = true;
 
-	if (pkcs11_cert || pkcs11_key) {
-		lib = getenv("PKCS11_MODULE_PATH");
-		if (!lib) {
-			fprintf(stdout,
-				"PKCS11_MODULE_PATH not set in the environment\n");
-			return -1;
-		}
-
-		gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
-		gnutls_global_init();
-
-		ret = gnutls_pkcs11_add_provider(lib, "trusted");
-		if (ret < 0) {
-			fprintf(stdout, "Failed to add pkcs11 provider\n");
-			return -1;
-		}
-	}
-
 	if (!pkcs11_cert) {
 		ret = read_bin_file(ctx->cert_file, &cert.data, &file_size);
 		if (ret < 0)
@@ -301,14 +332,9 @@ static int create_auth_data(struct auth_context *ctx)
 
 	/* load x509 certificate */
 	if (pkcs11_cert) {
-		ret = gnutls_pkcs11_obj_list_import_url4(&obj_list, &obj_list_size,
-							 ctx->cert_file, 0);
-		if (ret < 0 || obj_list_size == 0) {
-			fprintf(stdout, "Failed to import crt_file URI objects\n");
+		ret = import_pkcs11_crt(&x509, ctx);
+		if (ret < 0)
 			return -1;
-		}
-
-		gnutls_x509_crt_import_pkcs11(x509, obj_list[0]);
 	} else {
 		ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM);
 		if (ret < 0) {
@@ -320,12 +346,9 @@ static int create_auth_data(struct auth_context *ctx)
 
 	/* load a private key */
 	if (pkcs11_key) {
-		ret = gnutls_privkey_import_pkcs11_url(pkey, ctx->key_file);
-		if (ret < 0) {
-			fprintf(stderr, "error in %d: %s\n", __LINE__,
-				gnutls_strerror(ret));
+		ret = import_pkcs11_key(&pkey, ctx);
+		if (ret < 0)
 			return -1;
-		}
 	} else {
 		ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM,
 						     0, 0);
@@ -403,11 +426,6 @@ static int create_auth_data(struct auth_context *ctx)
 	 *   gnutls_free(signature.data);
 	 */
 
-	if (pkcs11_cert || pkcs11_key) {
-		gnutls_global_deinit();
-		gnutls_pkcs11_deinit();
-	}
-
 	return 0;
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-21 15:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 14:13 [PATCH v9] tools: mkeficapsule: Rework pkcs11 support Fabio Estevam via U-Boot
2026-07-21 15:16 ` Quentin Schulz via U-Boot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox