From: Wojciech Dubowik <[email protected]>

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 <[email protected]>
Cc: Franz Schnyder <[email protected]>
Signed-off-by: Wojciech Dubowik <[email protected]>
Signed-off-by: Fabio Estevam <[email protected]>
---
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

Reply via email to