[PATCH 0/5] pkcs11 decrypt provider based on p11-kit

19 views
Skip to first unread message

Bastian Germann

unread,
Dec 19, 2025, 6:22:23 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Bastian Germann, zachar...@gmail.com
Hi,

Based on the year-old submission by Matej Zachar, I am posting a PKCS#11
decrypt provider that depends on p11-kit only and replaces the existing
one that depends on both wolfSSL and p11-kit.

The wolfSSL PKCS#11 provider is converted to be a file-based AES decrypt
provider which the wolfSSL crypto implementation was able to provide
before the crypto providers were introduced.

This work of mine is not motivated by the subpar performance (as the
original submission claims) but by the fact that SWUpdate can only link to
old wolfSSL versions because of the recent GPL2 -> GPL3 license change.
Therefore, I got rid of the Debian package's pkcs11 profile and would
like to reintroduce it.

Just as a side note: I had to manually mangle the patch [0] available on
patchwork, which is butchered. Is there any other place where people can
download patches that were sent on the mailing list? This might be the
reason for different whitespace from the original submission.

Cheers,
Bastian

[0]: https://patchwork.ozlabs.org/project/swupdate/list/?series=428610

Bastian Germann (4):
crypto: Add swupdate_pkcs11.h
crypto: Make the p11-kit based module a decrypt provider
crypto: Make WolfSSL decrypt provider non-PKCS#11
test: Explicitly test pkcs11 crypto provider

Matej Zachar (1):
Increased PKCS#11 decryption performance with p11-kit

Makefile.flags | 2 -
crypto/Kconfig | 16 +-
crypto/Makefile | 6 +-
crypto/swupdate_decrypt_openssl.c | 5 +-
crypto/swupdate_decrypt_pkcs11_p11kit.c | 305 ++++++++++++++++++++++++
crypto/swupdate_decrypt_wolfssl.c | 211 +---------------
crypto/swupdate_pkcs11.h | 22 ++
crypto/swupdate_wolfssl.h | 20 +-
test/Makefile | 32 ++-
test/data/token/softhsm.conf | 2 +
test/test_crypt_pkcs11.c | 99 ++++++++
11 files changed, 481 insertions(+), 239 deletions(-)
create mode 100644 crypto/swupdate_decrypt_pkcs11_p11kit.c
create mode 100644 crypto/swupdate_pkcs11.h
create mode 100644 test/data/token/softhsm.conf
create mode 100644 test/test_crypt_pkcs11.c

Bastian Germann

unread,
Dec 19, 2025, 6:22:25 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Bastian Germann, zachar...@gmail.com
Add a header importing p11-kit stuff that is used for another PKCS#11
implementation.

Signed-off-by: Bastian Germann <ba...@debian.org>
---
crypto/swupdate_pkcs11.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 crypto/swupdate_pkcs11.h

diff --git a/crypto/swupdate_pkcs11.h b/crypto/swupdate_pkcs11.h
new file mode 100644
index 00000000..5658dc88
--- /dev/null
+++ b/crypto/swupdate_pkcs11.h
@@ -0,0 +1,22 @@
+/*
+ * (C) Copyright 2025
+ * Bastian Germann
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#pragma once
+
+#include <p11-kit/uri.h>
+#include <p11-kit/p11-kit.h>
+
+#include "util.h"
+
+struct pkcs11_digest {
+ P11KitUri *uri;
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session;
+ CK_MECHANISM mechanism;
+ CK_BYTE iv[AES_BLK_SIZE];
+ CK_BYTE last[AES_BLK_SIZE + 1];
+};

Bastian Germann

unread,
Dec 19, 2025, 6:22:25 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Bastian Germann, zachar...@gmail.com
Signed-off-by: Bastian Germann <ba...@debian.org>
---
crypto/swupdate_decrypt_pkcs11_p11kit.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/crypto/swupdate_decrypt_pkcs11_p11kit.c b/crypto/swupdate_decrypt_pkcs11_p11kit.c
index f66426bc..429c397a 100644
--- a/crypto/swupdate_decrypt_pkcs11_p11kit.c
+++ b/crypto/swupdate_decrypt_pkcs11_p11kit.c
@@ -13,6 +13,8 @@
#include "swupdate_pkcs11.h"
#include "util.h"

+static swupdate_decrypt_lib pkcs11;
+
static CK_SLOT_ID find_slot(CK_FUNCTION_LIST_PTR module, P11KitUri *uri)
{
CK_RV rv;
@@ -78,8 +80,8 @@ static CK_RV find_key(CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
return CKR_OK;
}

-struct pkcs11_digest *pkcs11_DECRYPT_init(unsigned char *uri,
- char __attribute__ ((__unused__)) keylen, unsigned char *iv, cipher_t cipher)
+static void *pkcs11_DECRYPT_init(unsigned char *uri,
+ char __attribute__ ((__unused__)) keylen, unsigned char *iv, cipher_t __attribute__ ((__unused__)) cipher)
{
struct pkcs11_digest *dgst;
CK_SLOT_ID slot_id;
@@ -185,9 +187,10 @@ free_digest:
return NULL;
}

-int pkcs11_DECRYPT_update(struct pkcs11_digest *dgst, unsigned char *buf,
+static int pkcs11_DECRYPT_update(void *ctx, unsigned char *buf,
int *outlen, const unsigned char *cryptbuf, int inlen)
{
+ struct pkcs11_digest *dgst = (struct pkcs11_digest *)ctx;
// precondition: len(buf) >= inlen + AES_BLK_SIZE
unsigned long buf_len = inlen + AES_BLK_SIZE;
CK_RV rv;
@@ -224,8 +227,9 @@ int pkcs11_DECRYPT_update(struct pkcs11_digest *dgst, unsigned char *buf,
return 0;
}

-int pkcs11_DECRYPT_final(struct pkcs11_digest *dgst, unsigned char *buf, int *outlen)
+static int pkcs11_DECRYPT_final(void *ctx, unsigned char *buf, int *outlen)
{
+ struct pkcs11_digest *dgst = (struct pkcs11_digest *)ctx;
CK_RV rv;
unsigned long extra_len = 0;

@@ -270,8 +274,9 @@ int pkcs11_DECRYPT_final(struct pkcs11_digest *dgst, unsigned char *buf, int *ou
return 0;
}

-void pkcs11_DECRYPT_cleanup(struct pkcs11_digest *dgst)
+static void pkcs11_DECRYPT_cleanup(void *ctx)
{
+ struct pkcs11_digest *dgst = (struct pkcs11_digest *)ctx;
if (dgst) {
if (dgst->uri)
p11_kit_uri_free(dgst->uri);
@@ -288,3 +293,13 @@ void pkcs11_DECRYPT_cleanup(struct pkcs11_digest *dgst)
dgst = NULL;
}
}
+
+__attribute__((constructor))
+static void pkcs11_probe(void)
+{
+ pkcs11.DECRYPT_init = pkcs11_DECRYPT_init;
+ pkcs11.DECRYPT_update = pkcs11_DECRYPT_update;
+ pkcs11.DECRYPT_final = pkcs11_DECRYPT_final;
+ pkcs11.DECRYPT_cleanup = pkcs11_DECRYPT_cleanup;
+ (void)register_cryptolib("pkcs11", &pkcs11);
+}

Bastian Germann

unread,
Dec 19, 2025, 6:22:25 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Matej Zachar
From: Matej Zachar <zachar...@gmail.com>

On platforms using "opTee + pkcs11 TA + RPMB" the decryption
speed is increased by order of magnitude - as the C_DecryptInit
context is not lost between decryption updates (C_DecryptUpdate).
On my board (iMX8MP) it went from 50min with wolfSSL to 3min with p11-kit

Signed-off-by: Matej Zachar <zachar...@gmail.com>
---
Makefile.flags | 2 -
crypto/Kconfig | 16 +-
crypto/Makefile | 6 +-
crypto/swupdate_decrypt_pkcs11_p11kit.c | 290 ++++++++++++++++++++++++
test/Makefile | 32 ++-
test/data/token/softhsm.conf | 2 +
test/test_crypt_pkcs11.c | 98 ++++++++
7 files changed, 429 insertions(+), 17 deletions(-)
create mode 100644 crypto/swupdate_decrypt_pkcs11_p11kit.c
create mode 100644 test/data/token/softhsm.conf
create mode 100644 test/test_crypt_pkcs11.c

diff --git a/Makefile.flags b/Makefile.flags
index 65f112e8..40dd3b66 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -163,8 +163,6 @@ endif
ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y)
KBUILD_CPPFLAGS += -DOPENSSL_ALL
LDLIBS += wolfssl
-else ifeq ($(CONFIG_PKCS11),y)
-LDLIBS += wolfssl
endif

ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 4b9db821..48eeb01c 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -21,6 +21,10 @@ menu "Crypto libraries"
config SSL_IMPL_GPGME
bool "gpgme"
depends on HAVE_GPGME
+
+ config PKCS11
+ bool "PKCS#11 (p11-kit)"
+ depends on HAVE_P11KIT
endmenu

config HASH_VERIFY
@@ -82,9 +86,9 @@ menu "Encryption"

config ENCRYPTED_IMAGES
bool "Images can be encrypted with a symmetric key"
- depends on SSL_IMPL_OPENSSL || SSL_IMPL_WOLFSSL || SSL_IMPL_MBEDTLS
+ depends on SSL_IMPL_OPENSSL || SSL_IMPL_WOLFSSL || SSL_IMPL_MBEDTLS || PKCS11
comment "Image encryption needs an SSL implementation"
- depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_WOLFSSL && !SSL_IMPL_MBEDTLS
+ depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_WOLFSSL && !SSL_IMPL_MBEDTLS && !PKCS11

config ENCRYPTED_SW_DESCRIPTION
bool "Even sw-description is encrypted"
@@ -126,13 +130,5 @@ config ENCRYPTED_IMAGES_HARDEN_LOGGING
hash mismatch and errors in the decryption finalization (padding) of a
streamed image are suppressed.

-config PKCS11
- bool "Enable PKCS#11 cryptographic operations"
- default n
- depends on SSL_IMPL_WOLFSSL && HAVE_P11KIT && ENCRYPTED_IMAGES
- help
- Enable using PKCS#11 for AES decryption instead of having the plain
- key available in a file. This is implemented with wolfSSL independent
- from the SSL implementation and replaces the plain key method.
endmenu

diff --git a/crypto/Makefile b/crypto/Makefile
index 25ab3ab7..b591ff57 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -14,10 +14,8 @@ endif
ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y)
obj-$(CONFIG_HASH_VERIFY) += swupdate_HASH_wolfssl.o
obj-$(CONFIG_SIGALG_CMS) += swupdate_pkcs7_verify_wolfssl.o
-ifeq ($(CONFIG_PKCS11),y)
obj-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_wolfssl.o
endif
-endif

ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y)
obj-$(CONFIG_HASH_VERIFY) += swupdate_HASH_mbedtls.o
@@ -28,3 +26,7 @@ endif
ifeq ($(CONFIG_SSL_IMPL_GPGME),y)
obj-$(CONFIG_SIGALG_GPG) += swupdate_gpg_verify.o
endif
+
+ifeq ($(CONFIG_PKCS11),y)
+obj-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11_p11kit.o
+endif
diff --git a/crypto/swupdate_decrypt_pkcs11_p11kit.c b/crypto/swupdate_decrypt_pkcs11_p11kit.c
new file mode 100644
index 00000000..f66426bc
--- /dev/null
+++ b/crypto/swupdate_decrypt_pkcs11_p11kit.c
@@ -0,0 +1,290 @@
+// SPDX-FileCopyrightText: 2024 Matej Zachar
+//
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Inspired by the wolfssl implementation done by Bastian Germann
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "swupdate_crypto.h"
+#include "swupdate_pkcs11.h"
+#include "util.h"
+
+static CK_SLOT_ID find_slot(CK_FUNCTION_LIST_PTR module, P11KitUri *uri)
+{
+ CK_RV rv;
+
+ CK_SLOT_ID slot_id = p11_kit_uri_get_slot_id(uri);
+ if (slot_id != (CK_SLOT_ID)-1)
+ return slot_id;
+
+ size_t slot_count;
+ rv = module->C_GetSlotList(1, NULL_PTR, &slot_count);
+ if (rv != CKR_OK)
+ return (CK_SLOT_ID)-1;
+
+ CK_SLOT_ID slot_ids[slot_count];
+ rv = module->C_GetSlotList(1, &slot_ids[0], &slot_count);
+ if (rv != CKR_OK)
+ return (CK_SLOT_ID)-1;
+
+ CK_TOKEN_INFO token_info;
+ for (int i = 0; i < slot_count; ++i) {
+ slot_id = slot_ids[i];
+
+ rv = module->C_GetTokenInfo(slot_id, &token_info);
+ if (rv != CKR_OK)
+ return (CK_SLOT_ID)-1;
+
+ if (p11_kit_uri_match_token_info(uri, &token_info))
+ return slot_id;
+ }
+
+ return (CK_SLOT_ID)-1;
+}
+
+static CK_RV find_key(CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
+ CK_ATTRIBUTE_PTR key_id, CK_OBJECT_HANDLE *key_handle)
+{
+ CK_RV rv;
+
+ CK_ATTRIBUTE find_template[] = {
+ { CKA_ID, key_id->pValue, key_id->ulValueLen }
+ };
+
+ rv = module->C_FindObjectsInit(session, find_template, 1);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+
+ CK_ULONG object_count;
+ rv = module->C_FindObjects(session, key_handle, 1, &object_count);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+
+ rv = module->C_FindObjectsFinal(session);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+
+ if (object_count == 0) {
+ return CKR_DATA_INVALID;
+ }
+
+ return CKR_OK;
+}
+
+struct pkcs11_digest *pkcs11_DECRYPT_init(unsigned char *uri,
+ char __attribute__ ((__unused__)) keylen, unsigned char *iv, cipher_t cipher)
+{
+ struct pkcs11_digest *dgst;
+ CK_SLOT_ID slot_id;
+ CK_ATTRIBUTE_PTR key_id;
+ const char *pin;
+ const char *module_path;
+ const char *msg;
+ int err = 0;
+ CK_RV rv;
+
+ if (uri == NULL || iv == NULL) {
+ ERROR("PKCS#11 URI or AES IV missing for decryption!");
+ return NULL;
+ }
+
+ dgst = calloc(1, sizeof(*dgst));
+ if (!dgst) {
+ return NULL;
+ }
+
+ dgst->uri = p11_kit_uri_new();
+ err = p11_kit_uri_parse((const char*)uri, P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE, dgst->uri);
+ if (err) {
+ msg = p11_kit_uri_message(err);
+ ERROR("PKCS#11 URI: %s", msg);
+ goto free_digest;
+ }
+
+ key_id = p11_kit_uri_get_attribute(dgst->uri, CKA_ID);
+ pin = p11_kit_uri_get_pin_value(dgst->uri);
+ module_path = p11_kit_uri_get_module_path(dgst->uri);
+ if (key_id == NULL || pin == NULL || module_path == NULL) {
+ ERROR("PKCS#11 URI must contain id, pin-value and module-path.");
+ goto free_digest;
+ }
+
+ dgst->module = p11_kit_module_load(module_path, 0);
+ if (dgst->module == NULL) {
+ msg = p11_kit_message();
+ ERROR("Failed to load PKCS#11 module [%s]: %s\n", module_path, msg);
+ goto free_digest;
+ }
+
+ rv = dgst->module->C_Initialize(NULL_PTR);
+ if (rv != CKR_OK)
+ goto err_msg;
+
+ slot_id = find_slot(dgst->module, dgst->uri);
+ if (slot_id == -1) {
+ ERROR("PKCS#11 URI must contain slot-id or token identification such as token, model, serial, manufacturer.");
+ goto free_digest;
+ }
+
+ rv = dgst->module->C_OpenSession(slot_id, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &dgst->session);
+ if (rv != CKR_OK)
+ goto err_msg;
+
+ rv = dgst->module->C_Login(dgst->session, CKU_USER, (unsigned char *)pin, strnlen(pin, 32));
+ if (rv != CKR_OK)
+ goto err_msg;
+
+ CK_OBJECT_HANDLE key;
+ rv = find_key(dgst->module, dgst->session, key_id, &key);
+ if (rv != CKR_OK)
+ goto err_msg;
+
+ // Setup a valid PKCS#7 block plus one state octet
+ for (int i = 0; i <= AES_BLK_SIZE; ++i) {
+ dgst->last[i] = AES_BLK_SIZE;
+ }
+
+ // Setup IV vector & mechanism
+ memcpy(dgst->iv, iv, AES_BLK_SIZE);
+ dgst->mechanism.mechanism = CKM_AES_CBC;
+ dgst->mechanism.pParameter = dgst->iv;
+ dgst->mechanism.ulParameterLen = AES_BLK_SIZE;
+
+ rv = dgst->module->C_DecryptInit(dgst->session, &dgst->mechanism, key);
+ if (rv != CKR_OK)
+ goto err_msg;
+
+ INFO("PKCS#11 key set up successfully.");
+ return dgst;
+
+err_msg:
+ msg = p11_kit_strerror(rv);
+ ERROR("PKCS#11 initialization failed: %s", msg);
+
+free_digest:
+ if (dgst->uri)
+ p11_kit_uri_free(dgst->uri);
+
+ if (dgst->session)
+ dgst->module->C_CloseSession(dgst->session);
+
+ if (dgst->module) {
+ dgst->module->C_Finalize(NULL_PTR);
+ p11_kit_module_release(dgst->module);
+ }
+
+ free(dgst);
+
+ return NULL;
+}
+
+int pkcs11_DECRYPT_update(struct pkcs11_digest *dgst, unsigned char *buf,
+ int *outlen, const unsigned char *cryptbuf, int inlen)
+{
+ // precondition: len(buf) >= inlen + AES_BLK_SIZE
+ unsigned long buf_len = inlen + AES_BLK_SIZE;
+ CK_RV rv;
+
+ if (inlen < AES_BLK_SIZE)
+ return -EFAULT;
+
+ if (dgst->last[AES_BLK_SIZE]) {
+ dgst->last[AES_BLK_SIZE] = 0;
+ // first run - there is no block to append
+ *outlen = 0;
+ } else {
+ // append previously decrypted last AES block
+ memcpy(buf, dgst->last, AES_BLK_SIZE);
+ buf += AES_BLK_SIZE;
+ *outlen = AES_BLK_SIZE;
+ }
+
+ rv = dgst->module->C_DecryptUpdate(dgst->session, (unsigned char*)cryptbuf, inlen, buf, &buf_len);
+ if (rv != CKR_OK) {
+ ERROR("PKCS#11 AES decryption failed: %s", p11_kit_strerror(rv));
+ return -EFAULT;
+ }
+
+ // strip and remember last AES block from decoded buffer
+ // it will get appended either in the next call to DECRYPT_update or DECRYPT_final
+ buf_len -= AES_BLK_SIZE;
+ memcpy(dgst->last, &buf[buf_len], AES_BLK_SIZE);
+
+ // update iv for the next block
+ memcpy(dgst->iv, cryptbuf + inlen - AES_BLK_SIZE, AES_BLK_SIZE);
+
+ *outlen += (int)buf_len;
+ return 0;
+}
+
+int pkcs11_DECRYPT_final(struct pkcs11_digest *dgst, unsigned char *buf, int *outlen)
+{
+ CK_RV rv;
+ unsigned long extra_len = 0;
+
+ if (dgst->last[AES_BLK_SIZE]) {
+#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING
+ ERROR("AES: At least one call to pkcs11_DECRYPT_update was expected");
+#endif
+ return -EINVAL;
+ }
+
+ // append previously decrypted last AES block if any
+ memcpy(buf, dgst->last, AES_BLK_SIZE);
+
+ rv = dgst->module->C_DecryptFinal(dgst->session, &buf[AES_BLK_SIZE], &extra_len);
+ if (rv != CKR_OK)
+ return -EFAULT;
+
+ // obtain last AES block after C_DecryptFinal
+ CK_BYTE_PTR last = &buf[extra_len];
+
+ // Handle manual PKCS#7 padding removal
+ CK_BYTE padding_value = last[AES_BLK_SIZE - 1];
+
+ if (padding_value <= 0 || padding_value > AES_BLK_SIZE) {
+#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING
+ ERROR("AES: Invalid PKCS#7 padding value [%u]", padding_value);
+#endif
+ return -EFAULT;
+ }
+
+ // Verify that padding is correct
+ for (CK_BYTE i = 0; i < padding_value; ++i) {
+ if (last[AES_BLK_SIZE - 1 - i] != padding_value) {
+#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING
+ ERROR("AES: Invalid PKCS#7 padding value [%u] at offset %u", padding_value, i);
+#endif
+ return -EINVAL;
+ }
+ }
+
+ *outlen = (int)extra_len + AES_BLK_SIZE - padding_value;
+ return 0;
+}
+
+void pkcs11_DECRYPT_cleanup(struct pkcs11_digest *dgst)
+{
+ if (dgst) {
+ if (dgst->uri)
+ p11_kit_uri_free(dgst->uri);
+
+ if (dgst->session)
+ dgst->module->C_CloseSession(dgst->session);
+
+ if (dgst->module) {
+ dgst->module->C_Finalize(NULL_PTR);
+ p11_kit_module_release(dgst->module);
+ }
+
+ free(dgst);
+ dgst = NULL;
+ }
+}
diff --git a/test/Makefile b/test/Makefile
index 385efd85..8bdf50d6 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -17,9 +17,10 @@
## along with this program; if not, write to the Free Software
## Foundation, Inc.

-ifneq ($(CONFIG_PKCS11),y)
-tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt
+ifeq ($(CONFIG_PKCS11),y)
+tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt_pkcs11
endif
+tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt
tests-$(CONFIG_HASH_VERIFY) += test_hash
ifeq ($(CONFIG_SIGALG_RAWRSA),y)
tests-$(CONFIG_SIGNED_IMAGES) += test_verify
@@ -66,7 +67,7 @@ quiet_cmd_linktestexe = LD $(basename $@)
"$(SWLIBS)" \
"$(LDLIBS) cmocka"

-EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; LD_LIBRARY_PATH=$(objtree) CMOCKA_MESSAGE_OUTPUT=TAP $(var)
+EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; LD_LIBRARY_PATH=$(objtree) CMOCKA_MESSAGE_OUTPUT=TAP SOFTHSM2_CONF=$(DATADIR)/token/softhsm.conf $(var)

PHONY += default
default:
@@ -111,4 +112,29 @@ $(DATADIR)/signing-secret.pem:
$(if $(Q),@echo " GEN $@")
$(Q)openssl genrsa -out $@ 2>/dev/null

+ifeq ($(CONFIG_PKCS11),y)
+$(obj)/test_crypt_pkcs11.o: $(DATADIR)/softshm
+
+TOKEN_AES_KEY := dd020ce5ebd5c468556288d6a75169c88a5b335d9f569e30751c50401467d230
+TOKEN_AES_IV := c1f390d21dd06118cbd333144a3318ca
+
+.INTERMEDIATE: $(DATADIR)/softshm
+$(DATADIR)/softshm: export SOFTHSM2_CONF=$(DATADIR)/token/softhsm.conf
+$(DATADIR)/softshm: $(DATADIR)/token/softhsm.conf
+ $(if $(Q),@echo " INIT $@")
+ $(Q)rm -rf $(DATADIR)/token/*/
+
+ $(if $(Q),@echo " GEN $(DATADIR)/token/original.data")
+ $(Q)openssl rand 131075 > $(DATADIR)/token/original.data
+
+ $(if $(Q),@echo " ENCRYPT $(DATADIR)/token/original.data")
+ $(Q)openssl enc -aes-256-cbc -in $(DATADIR)/token/original.data -out $(DATADIR)/token/encrypted.data -K $(TOKEN_AES_KEY) -iv $(TOKEN_AES_IV)
+ $(Q)echo -n "$(TOKEN_AES_IV)" | xxd -p -r > $(DATADIR)/token/encrypted.data.iv
+
+ $(if $(Q),@echo " IMPORT $(DATADIR)/token/aes.key")
+ $(Q)echo -n "$(TOKEN_AES_KEY)" | xxd -p -r > $(DATADIR)/token/aes.key
+ $(Q)softhsm2-util --init-token --slot 0 --label "TestToken" --so-pin 123456 --pin 1234
+ $(Q)softhsm2-util --import $(DATADIR)/token/aes.key --aes --token "TestToken" --label "AES key" --id A1B2 --pin 1234
+endif
+
.PHONY: $(PHONY)
diff --git a/test/data/token/softhsm.conf b/test/data/token/softhsm.conf
new file mode 100644
index 00000000..bd43fe45
--- /dev/null
+++ b/test/data/token/softhsm.conf
@@ -0,0 +1,2 @@
+directories.tokendir = test/data/token
+objectstore.backend = file
\ No newline at end of file
diff --git a/test/test_crypt_pkcs11.c b/test/test_crypt_pkcs11.c
new file mode 100644
index 00000000..94ed92a8
--- /dev/null
+++ b/test/test_crypt_pkcs11.c
@@ -0,0 +1,98 @@
+// SPDX-FileCopyrightText: 2024 Matej Zachar
+//
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <util.h>
+#include "swupdate_crypto.h"
+
+#define BUFFER_SIZE (AES_BLK_SIZE * 1024)
+#define TOKENDIR "test/data/token"
+
+static int read_file(const char *path, unsigned char *buffer, size_t *size)
+{
+ FILE *fp = fopen(path, "r");
+ if (!fp) {
+ fprintf(stderr, "Failed to open file '%s'\n", path);
+ return -1;
+ }
+
+ size_t len = fread(buffer, sizeof(char), *size, fp);
+ if (ferror(fp) != 0) {
+ fprintf(stderr, "Error reading file '%s'\n", path);
+ fclose(fp);
+ return -1;
+ }
+
+ *size = len;
+ fclose(fp);
+
+ return 0;
+}
+
+static void test_crypt_pkcs11_256(void **state)
+{
+ (void) state;
+ int err;
+
+ const char * uri = "pkcs11:token=TestToken;id=%A1%B2?pin-value=1234&module-path=/usr/lib/softhsm/libsofthsm2.so";
+
+ size_t original_data_len = 128 * 1024;/* 128KiB */
+ unsigned char original_data[original_data_len];
+ err = read_file(TOKENDIR "/original.data", &original_data[0], &original_data_len);
+ assert_true(err == 0);
+
+ size_t encrypted_data_len = 128 * 1024 + AES_BLK_SIZE;/* 128KiB AES_BLK_SIZE(16B) */
+ unsigned char encrypted_data[encrypted_data_len];
+ err = read_file(TOKENDIR "/encrypted.data", &encrypted_data[0], &encrypted_data_len);
+ assert_true(err == 0);
+
+ unsigned char decrypted_data[encrypted_data_len];
+
+ size_t iv_size = 16;
+ unsigned char iv[iv_size];
+ err = read_file(TOKENDIR "/encrypted.data.iv", &iv[0], &iv_size);
+ assert_true(err == 0);
+
+ unsigned char buffer[BUFFER_SIZE + AES_BLK_SIZE];
+
+ struct swupdate_digest *dgst = swupdate_DECRYPT_init((unsigned char *)uri, 0, &iv[0], AES_CBC_256);
+ assert_non_null(dgst);
+
+ int len;
+ size_t e_offset = 0;
+ size_t d_offset = 0;
+ while (e_offset < encrypted_data_len) {
+ size_t chunk_size = (encrypted_data_len - e_offset > BUFFER_SIZE) ? BUFFER_SIZE : encrypted_data_len - e_offset;
+
+ err = swupdate_DECRYPT_update(dgst, buffer, &len, encrypted_data + e_offset, chunk_size);
+ assert_true(err == 0);
+ assert_true(len >= AES_BLK_SIZE && len <= chunk_size);
+ e_offset += chunk_size;
+
+ memcpy(&decrypted_data[d_offset], buffer, len);
+ d_offset += len;
+ }
+
+ err = swupdate_DECRYPT_final(dgst, buffer, &len);
+ assert_true(err == 0);
+ assert_true(len == 3); /* as the size is 128*1024+3 */
+
+ memcpy(&decrypted_data[d_offset], buffer, len);
+ d_offset += len;
+
+ assert_true(strncmp((const char *)decrypted_data, (const char *)original_data, original_data_len) == 0);
+}
+
+int main(void)
+{
+ const struct CMUnitTest crypt_pkcs11_tests[] = {
+ cmocka_unit_test(test_crypt_pkcs11_256)
+ };
+ return cmocka_run_group_tests_name("crypt_pkcs11", crypt_pkcs11_tests, NULL, NULL);
+}

Bastian Germann

unread,
Dec 19, 2025, 6:22:26 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Bastian Germann, zachar...@gmail.com
The WolfSSL decrypt provider offers AES decryption via file-based
keys now by including the corresponding openssl module similar to
swupdate_HASH_wolfssl.

Align the name (previously lowercase) with the other WolfSSL providers.

Signed-off-by: Bastian Germann <ba...@debian.org>
---
crypto/swupdate_decrypt_openssl.c | 5 +-
crypto/swupdate_decrypt_wolfssl.c | 211 ++----------------------------
crypto/swupdate_wolfssl.h | 20 +--
3 files changed, 14 insertions(+), 222 deletions(-)

diff --git a/crypto/swupdate_decrypt_openssl.c b/crypto/swupdate_decrypt_openssl.c
index e6ea3ffd..5edf150f 100644
--- a/crypto/swupdate_decrypt_openssl.c
+++ b/crypto/swupdate_decrypt_openssl.c
@@ -13,12 +13,13 @@
#include <stdbool.h>
#include <unistd.h>
#include "swupdate.h"
+#if !defined(NO_INCLUDE_OPENSSL)
+#define MODNAME "opensslAES"
#include "swupdate_openssl.h"
+#endif
#include "util.h"
#include "swupdate_crypto.h"

-#define MODNAME "opensslAES"
-
static void openssl_probe(void);

static swupdate_decrypt_lib openssl;
diff --git a/crypto/swupdate_decrypt_wolfssl.c b/crypto/swupdate_decrypt_wolfssl.c
index 015fcd3c..0ecc953f 100644
--- a/crypto/swupdate_decrypt_wolfssl.c
+++ b/crypto/swupdate_decrypt_wolfssl.c
@@ -1,212 +1,19 @@
/*
- * (C) Copyright 2020, Linutronix GmbH
- * Author: Bastian Germann
+ * (C) Copyright 2024
+ * Stefano Babic, stefan...@swupdate.org.
*
* SPDX-License-Identifier: GPL-2.0-only
*/

-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+
#include "swupdate.h"
#include "swupdate_wolfssl.h"
-#include "util.h"
-#include <wolfssl/wolfcrypt/error-crypt.h>
-#include <wolfssl/wolfcrypt/logging.h>
-#include "swupdate_crypto.h"
-
-static swupdate_decrypt_lib wolfssl;
-
-#ifdef DEBUG_WOLFSSL
-static void wolfssl_debug(int __attribute__ ((__unused__)) level, const char *const msg)
-{
- DEBUG("%s", msg);
-}
-#endif
-
-static void *wolfssl_DECRYPT_init(unsigned char *key,
- char __attribute__ ((__unused__)) keylen, unsigned char *iv,
- cipher_t cipher)
-{
- struct wolfssl_digest *dgst;
- const char *library;
- const char *pin;
- const char *msg;
- CK_ATTRIBUTE_PTR key_id;
- int slot_id;
- int err = 0;
- int dev_id = 1;
-
- const char *uri = (const char *)key;
- if ((uri == NULL) || (iv == NULL)) {
- ERROR("PKCS#11 URI or AES IV missing for decryption!");
- return NULL;
- }
-
- /* Temporary to remove warning */
- cipher = cipher;
-
- dgst = calloc(1, sizeof(*dgst));
- if (!dgst) {
- return NULL;
- }
-
- dgst->p11uri = p11_kit_uri_new();
- err = p11_kit_uri_parse(uri, P11_KIT_URI_FOR_ANY, dgst->p11uri);
- if (err) {
- msg = p11_kit_uri_message(err);
- ERROR("PKCS#11 URI: %s", msg);
- free(dgst);
- return NULL;
- }
-
- slot_id = p11_kit_uri_get_slot_id(dgst->p11uri);
- key_id = p11_kit_uri_get_attribute(dgst->p11uri, CKA_ID);
- pin = p11_kit_uri_get_pin_value(dgst->p11uri);
- library = p11_kit_uri_get_module_path(dgst->p11uri);
- if (slot_id == -1 || key_id == NULL || pin == NULL || library == NULL) {
- ERROR("PKCS#11 URI must contain slot-id, id, pin-value, and module-path.");
- goto err_free;
- }
-
- // Set up a valid PKCS#7 block plus one state octet
- for (int i = 0; i <= AES_BLK_SIZE; i++) {
- dgst->last_decr[i] = AES_BLK_SIZE;
- }
-
-#ifdef DEBUG_WOLFSSL
- wolfSSL_SetLoggingCb(wolfssl_debug);
- wolfSSL_Debugging_ON();
-#endif
- wolfCrypt_Init();
- err = wc_Pkcs11_Initialize(&dgst->pkdev, library, NULL);
- if (err)
- goto err_msg;
-
- err = wc_Pkcs11Token_Init(&dgst->pktoken, &dgst->pkdev, slot_id,
- "unspecified", (unsigned char *)pin, strlen(pin));
- if (err)
- goto err_msg;
-
- err = wc_Pkcs11Token_Open(&dgst->pktoken, 0);
- if (err)
- goto err_msg;
-
- err = wc_CryptoCb_RegisterDevice(dev_id, wc_Pkcs11_CryptoDevCb, &dgst->pktoken);
- if (err)
- goto err_msg;
-
- err = wc_AesInit_Id(&dgst->ctxdec, key_id->pValue, key_id->ulValueLen, NULL, dev_id);
- if (err)
- goto err_msg;
-
- err = wc_AesSetIV(&dgst->ctxdec, iv);
- if (err)
- goto err_msg;
-
- INFO("PKCS#11 key set up successfully.");
- return dgst;

-err_msg:
- msg = wc_GetErrorString(err);
- ERROR("PKCS#11 initialization failed: %s", msg);
-
-err_free:
- wc_Pkcs11Token_Final(&dgst->pktoken);
- wc_Pkcs11_Finalize(&dgst->pkdev);
-
- p11_kit_uri_free(dgst->p11uri);
- free(dgst);
-
- return NULL;
-}
-
-static int wolfssl_DECRYPT_update(void *ctx, unsigned char *buf,
- int *outlen, const unsigned char *cryptbuf, int inlen)
-{
- struct wolfssl_digest *dgst = (struct wolfssl_digest *)ctx;
- // precondition: len(buf) >= inlen + AES_BLK_SIZE
- unsigned char *pad_buf = &buf[AES_BLK_SIZE];
- const char *msg;
- int err;
- int one_off_sz = inlen - AES_BLK_SIZE;
-
- if (inlen < AES_BLK_SIZE)
- return -EFAULT;
-
- if (dgst->last_decr[AES_BLK_SIZE]) {
- // This is for the first decryption operation
- pad_buf = buf;
- dgst->last_decr[AES_BLK_SIZE] = 0;
- *outlen = one_off_sz;
- } else {
- memcpy(buf, dgst->last_decr, AES_BLK_SIZE);
- *outlen = inlen;
- }
-
- err = wc_AesCbcDecrypt(&dgst->ctxdec, pad_buf, cryptbuf, inlen);
- if (err) {
- msg = wc_GetErrorString(err);
- ERROR("PKCS#11 AES decryption failed: %s", msg);
- return -EFAULT;
- }
- // Remember the last decrypted block which might contain padding
- memcpy(dgst->last_decr, &pad_buf[one_off_sz], AES_BLK_SIZE);
-
- wc_AesSetIV(&dgst->ctxdec, &cryptbuf[one_off_sz]);
-
- return 0;
-}
-
-// Gets rid of PKCS#7 padding
-static int wolfssl_DECRYPT_final(void *ctx, unsigned char *buf, int *outlen)
-{
- struct wolfssl_digest *dgst = (struct wolfssl_digest *)ctx;
- unsigned char last_oct = dgst->last_decr[AES_BLK_SIZE - 1];
- if (last_oct > AES_BLK_SIZE || last_oct == 0) {
-#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING
- ERROR("AES: Invalid PKCS#7 padding.");
-#endif
- return -EFAULT;
- }
-
- for (int i = 2; i <= last_oct; i++) {
- if (dgst->last_decr[AES_BLK_SIZE - i] != last_oct) {
-#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING
- ERROR("AES: Invalid PKCS#7 padding.");
-#endif
- return -EFAULT;
- }
- }
-
- *outlen = AES_BLK_SIZE - last_oct;
- memcpy(buf, dgst->last_decr, *outlen);
-
- return 0;
-}
-
-static void wolfssl_DECRYPT_cleanup(void *ctx)
-{
- struct wolfssl_digest *dgst = (struct wolfssl_digest *)ctx;
- if (dgst) {
- wc_Pkcs11Token_Final(&dgst->pktoken);
- wc_Pkcs11_Finalize(&dgst->pkdev);
- p11_kit_uri_free(dgst->p11uri);
-
- free(dgst);
- dgst = NULL;
- }
+/*
+ * Switch to WolfSSL in module
+ */
+#define NO_INCLUDE_OPENSSL
+#define MODNAME "WolfSSL"

- wolfCrypt_Cleanup();
-}
+#include "swupdate_decrypt_openssl.c"

-__attribute__((constructor))
-static void wolfssl_probe(void)
-{
- wolfssl.DECRYPT_init = wolfssl_DECRYPT_init;
- wolfssl.DECRYPT_update = wolfssl_DECRYPT_update;
- wolfssl.DECRYPT_final = wolfssl_DECRYPT_final;
- wolfssl.DECRYPT_cleanup = wolfssl_DECRYPT_cleanup;
- (void)register_cryptolib("wolfssl", &wolfssl);
-}
diff --git a/crypto/swupdate_wolfssl.h b/crypto/swupdate_wolfssl.h
index 00f18714..73e4c57e 100644
--- a/crypto/swupdate_wolfssl.h
+++ b/crypto/swupdate_wolfssl.h
@@ -10,16 +10,6 @@
#include <stdint.h>
#include "util.h"

-#ifdef CONFIG_PKCS11
-#include <wolfssl/options.h>
-#include <wolfssl/ssl.h>
-#include <wolfssl/wolfcrypt/aes.h>
-#include <wolfssl/wolfcrypt/wc_pkcs11.h>
-// Exclude p11-kit's pkcs11.h to prevent conflicting with wolfssl's
-#define PKCS11_H 1
-#include <p11-kit/uri.h>
-#endif
-
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/openssl/bio.h>
@@ -34,7 +24,7 @@
#include <wolfssl/openssl/opensslv.h>
#include <wolfssl/openssl/pkcs7.h>

-#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) (1)
+#define SSL_GET_CTXDEC(dgst) dgst->ctxdec

#define X509_PURPOSE_CODE_SIGN EXTKEYUSE_CODESIGN
#define SSL_PURPOSE_EMAIL_PROT EXTKEYUSE_EMAILPROT
@@ -46,11 +36,5 @@ struct wolfssl_digest {
EVP_PKEY_CTX *ckey; /* this is used for RSA key */
X509_STORE *certs; /* this is used if CMS is set */
EVP_MD_CTX *ctx;
-#ifdef CONFIG_PKCS11
- unsigned char last_decr[AES_BLOCK_SIZE + 1];
- P11KitUri *p11uri;
- Aes ctxdec;
- Pkcs11Dev pkdev;
- Pkcs11Token pktoken;
-#endif
+ EVP_CIPHER_CTX *ctxdec;
};

Bastian Germann

unread,
Dec 19, 2025, 6:22:26 AM (2 days ago) Dec 19
to swup...@googlegroups.com, Bastian Germann, zachar...@gmail.com
Using the default crypto provider does not work with the pkcs11
decryption test. Set the right provider.

Signed-off-by: Bastian Germann <ba...@debian.org>
---
test/test_crypt_pkcs11.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/test/test_crypt_pkcs11.c b/test/test_crypt_pkcs11.c
index 94ed92a8..f7b851ef 100644
--- a/test/test_crypt_pkcs11.c
+++ b/test/test_crypt_pkcs11.c
@@ -61,6 +61,7 @@ static void test_crypt_pkcs11_256(void **state)

unsigned char buffer[BUFFER_SIZE + AES_BLK_SIZE];

+ set_cryptolib("pkcs11");
struct swupdate_digest *dgst = swupdate_DECRYPT_init((unsigned char *)uri, 0, &iv[0], AES_CBC_256);
assert_non_null(dgst);

ayoub...@googlemail.com

unread,
Dec 19, 2025, 8:39:57 AM (2 days ago) Dec 19
to swupdate
The problem is in WolfSSL :

I raised an issue a while ago but it still open:

To reimplement the decyprtion in Swupdate to overcome WolfSSL PKS11 decryption problem I find it a bit wild.
Reply all
Reply to author
Forward
0 new messages