new file mode 100644
@@ -0,0 +1,236 @@
+From: Johannes Schneider <johannes.schneider@leica-geosystems.com>
+Subject: cst: port pkcs11 signing from the OpenSSL ENGINE to a provider
+
+OpenSSL 4.0 removed the ENGINE API, so CST's pkcs11-backed signing stops
+working: ENGINE_by_id("pkcs11") returns NULL and engine_ctx_init() fails.
+
+Reimplement the pkcs11 certificate and key loading on OSSL_STORE and the
+pkcs11 provider. engine_ctx_init() loads the default and pkcs11 providers --
+default explicitly, because activating any provider stops OpenSSL
+auto-loading default, which would drop the EVP digest and signature algorithms
+the signer needs. ENGINE_load_certificate()/ENGINE_load_key() open the pkcs11
+URI through OSSL_STORE and return the X509 / EVP_PKEY, feeding the existing CMS
+and EVP signing unchanged. The public entry points keep their names and
+signatures; the ENGINE * argument is now vestigial. The PIN travels in the URI
+(pin-value=).
+
+Upstream-Status: Pending
+Assisted-by: Claude:claude-opus-4-8
+Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
+---
+Builds on the engine-stub change already in this recipe's series
+(0015-fix-openssl-4-engine-api-removal), which only makes the file compile and
+noted that pkcs11-backed signing was still unavailable on OpenSSL 4; this
+restores it.
+--- a/src/lib/back_end/engine.c
++++ b/src/lib/back_end/engine.c
+@@ -7,8 +7,9 @@
+ /*
+ * OpenSSL 4.0 removed the ENGINE API. <openssl/engine.h> still declares
+ * it for source compatibility, and defining OPENSSL_ENGINE_STUBS turns the
+- * declarations into inline no-ops so this file keeps linking. The pkcs11
+- * engine simply does not exist there, which engine_ctx_init() reports.
++ * declarations into inline no-ops so this file keeps linking. Signing no
++ * longer uses an engine (see engine_ctx_init); the vestigial ENGINE * only
++ * keeps the public entry points' signatures unchanged.
+ */
+ #define OPENSSL_ENGINE_STUBS
+
+@@ -19,6 +20,8 @@
+ #include <openssl/err.h>
+ #include <openssl/x509.h>
+ #include <openssl/evp.h>
++#include <openssl/provider.h>
++#include <openssl/store.h>
+ #include <stdint.h>
+
+ #if CST_WITH_PKCS11
+@@ -31,6 +34,76 @@
+ }
+ #endif
+
++/* Load default and pkcs11 once; "default" explicitly, or activating pkcs11 stops OpenSSL auto-loading it and the signer loses its EVP algorithms. */
++static int load_providers(void)
++{
++ static int loaded;
++
++ if (loaded)
++ return 1;
++
++ if (!OSSL_PROVIDER_load(NULL, "default")) {
++ fprintf(stderr, "ERROR: cannot load the default OpenSSL provider\n");
++ return 0;
++ }
++ if (!OSSL_PROVIDER_load(NULL, "pkcs11")) {
++ fprintf(stderr, "ERROR: cannot load the pkcs11 OpenSSL provider; "
++ "is pkcs11-provider installed and OPENSSL_MODULES set?\n");
++ return 0;
++ }
++
++ loaded = 1;
++ return 1;
++}
++
++/* Load a certificate and/or key from a PKCS#11 (or any OSSL_STORE) URI; returns 1 only if every requested object was found. */
++static int store_load(const char *uri, X509 **cert_out, EVP_PKEY **key_out)
++{
++ OSSL_STORE_CTX *store = NULL;
++ int ok = 0;
++
++ if (!uri)
++ return 0;
++
++ store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL);
++ if (!store) {
++ fprintf(stderr, "ERROR: cannot open PKCS#11 store for %s\n", uri);
++ return 0;
++ }
++
++ while (!OSSL_STORE_eof(store)) {
++ OSSL_STORE_INFO *info = OSSL_STORE_load(store);
++
++ if (!info) {
++ /* NULL means EOF or a non-fatal error; break on the error flag, or a bad object spins forever (eof stays 0). */
++ if (OSSL_STORE_error(store))
++ break;
++ continue;
++ }
++
++ switch (OSSL_STORE_INFO_get_type(info)) {
++ case OSSL_STORE_INFO_CERT:
++ if (cert_out && !*cert_out)
++ *cert_out = OSSL_STORE_INFO_get1_CERT(info);
++ break;
++ case OSSL_STORE_INFO_PKEY:
++ if (key_out && !*key_out)
++ *key_out = OSSL_STORE_INFO_get1_PKEY(info);
++ break;
++ default:
++ break;
++ }
++ OSSL_STORE_INFO_free(info);
++
++ if ((!cert_out || *cert_out) && (!key_out || *key_out))
++ break;
++ }
++
++ OSSL_STORE_close(store);
++ ok = (!cert_out || *cert_out) && (!key_out || *key_out);
++ return ok;
++}
++
+ struct engine_ctx *engine_ctx_new(void)
+ {
+ struct engine_ctx *ctx = NULL;
+@@ -41,16 +114,13 @@
+
+ int32_t engine_ctx_destroy(struct engine_ctx *ctx)
+ {
+- if (ctx) {
+- ENGINE_free(ctx->engine);
++ if (ctx)
+ OPENSSL_free(ctx);
+- }
+ return 1;
+ }
+
+ int32_t engine_ctx_init(struct engine_ctx *ctx)
+ {
+- dynamic_fns fns;
+ /* OpenSSL Initialization */
+ #if OPENSSL_VERSION_NUMBER >= 0x10100000
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS |
+@@ -66,60 +136,46 @@
+
+ ERR_clear_error();
+
+- ENGINE_load_builtin_engines();
+-
+- ctx->engine = ENGINE_by_id("pkcs11");
+-
+- if (!ctx->engine) {
+- fprintf(stderr, "ERROR: cannot load the pkcs11 OpenSSL engine\n");
+-#if OPENSSL_VERSION_MAJOR >= 4
+- fprintf(stderr,
+- "ERROR: OpenSSL 4.0 removed ENGINE support, so PKCS#11 "
+- "backed signing is unavailable\n");
+-#endif
++ if (!load_providers())
+ return 0;
+- }
+
+-#ifdef DEBUG
+- ENGINE_ctrl_cmd_string(ctx->engine, "VERBOSE", NULL, 0);
+-#endif
+-
+- if (!ENGINE_init(ctx->engine)) {
+- ENGINE_free(ctx->engine);
+- return 0;
+- }
++ ctx->engine = NULL;
+
+ return 1;
+ }
+
+ int32_t engine_ctx_finish(struct engine_ctx *ctx)
+ {
+- if (ctx)
+- ENGINE_finish(ctx->engine);
++ (void)ctx;
+ return 1;
+ }
+
+ X509 *ENGINE_load_certificate(ENGINE *e, const char *cert_ref)
+ {
+- struct {
+- const char *s_slot_cert_id;
+- X509 *cert;
+- } params = {0};
++ X509 *cert = NULL;
+
+- params.s_slot_cert_id = cert_ref;
+- params.cert = NULL;
++ (void)e;
+
+- if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) {
++ if (!store_load(cert_ref, &cert, NULL)) {
+ ERR_print_errors_fp(stderr);
+ return NULL;
+ }
+
+- return params.cert;
++ return cert;
+ }
+
+ EVP_PKEY *ENGINE_load_key(ENGINE *e, const char *key_ref)
+ {
+- return ENGINE_load_private_key(e, key_ref, 0, 0);
++ EVP_PKEY *key = NULL;
++
++ (void)e;
++
++ if (!store_load(key_ref, NULL, &key)) {
++ ERR_print_errors_fp(stderr);
++ return NULL;
++ }
++
++ return key;
+ }
+
+ X509 *engine_read_certificate(const char *cert_ref)
+@@ -161,14 +217,8 @@
+ #endif
+
+ out:
+- if (ctx) {
+- /*
+- * Destroy the context: ctx_finish is not called here since
+- * ENGINE_finish cleanups the engine instance. Calling ctx_destroy
+- * next will lead to null pointer dereference.
+- */
++ if (ctx)
+ engine_ctx_destroy(ctx);
+- }
+
+ if (error)
+ ERR_print_errors_fp(stderr);
@@ -29,6 +29,7 @@ SRC_URI = "\
file://0014-fix-pointer-sign-errors-with-clang.patch \
file://0015-fix-openssl-4-engine-api-removal.patch \
file://0016-fix-openssl-4-const-subject-name.patch \
+ file://0017-cst-port-pkcs11-signing-from-engine-to-provider.patch \
"
SRC_URI[sha256sum] = "fd92a1a9faa10fb81bbf752c7ee1e257f17e1ec4c2964f8a47adf8a3eaa7df41"
0015-fix-openssl-4-engine-api-removal made CST build against OpenSSL 4 by stubbing out the removed ENGINE API, but left PKCS#11-backed signing broken: ENGINE_by_id("pkcs11") returns NULL, so engine_ctx_init() fails. Add a patch that reimplements the pkcs11 certificate and key loading on OSSL_STORE and the pkcs11 provider (pkcs11-provider), restoring HSM/token-backed signing on OpenSSL 4. OpenSSL 3 builds are unaffected. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> --- ...cs11-signing-from-engine-to-provider.patch | 236 ++++++++++++++++++ .../recipes-support/imx-cst/imx-cst_4.0.1.bb | 1 + 2 files changed, 237 insertions(+) create mode 100644 meta-oe/recipes-support/imx-cst/imx-cst/0017-cst-port-pkcs11-signing-from-engine-to-provider.patch base-commit: cf030e73b8e0fa463a81ace8f13c82a9f1281ebe