From 4f00942078c2439271c74144dcd900c63eb29478 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 24 Dec 2025 04:54:13 +0100 Subject: [PATCH 1/2] Add PKCS11 backend for encrypted partitions --- docs/encrypted_partitions.md | 30 +++++ include/encrypt.h | 15 +++ include/user_settings.h | 6 +- include/wolfboot/wolfboot.h | 5 + options.mk | 38 ++++-- src/libwolfboot.c | 242 ++++++++++++++++++++++++++++++++++- src/update_flash.c | 8 +- 7 files changed, 326 insertions(+), 18 deletions(-) diff --git a/docs/encrypted_partitions.md b/docs/encrypted_partitions.md index 1486428677..5ac13d2085 100644 --- a/docs/encrypted_partitions.md +++ b/docs/encrypted_partitions.md @@ -73,6 +73,36 @@ To compile wolfBoot with encryption support, use the option `ENCRYPT=1`. By default, this also selects `ENCRYPT_WITH_CHACHA=1`. To use AES encryption instead, select `ENCRYPT_WITH_AES128=1` or `ENCRYPT_WITH_AES256=1`. +### PKCS#11 backend + +On ARM TrustZone configurations with `WOLFCRYPT_TZ_PKCS11` enabled, it is +possible to use the keyvault provided by wolfBoot to store the encryption key. +To enable this, use the configuration option `ENCRYPT_PKCS11=1` alongside +`WOLFCRYPT_TZ=1`, `WOLFCRYPT_TZ_PKCS11=1` and `ENCRYPT=1`, and set +`ENCRYPT_PKCS11_PIN` to the user PIN for the PKCS#11 vault. This should be set +in the form of a C string literal, for example +`ENCRYPT_PKCS11_PIN="\x01\x02\x03\x04"`, and the ending null byte will be +ignored. + +When this is enabled, instead of providing the key to wolfBoot via +`wolfBoot_set_encrypt_key`, the application should use the PKCS#11 API to store +it in the keyvault with an appropriate ID (via the `CKA_ID` attribute). This ID +should then be used as the `key` parameter (in place of the key) when calling +`wolfBoot_set_encrypt_key`. + +The following configuration options are also available: + +- `ENCRYPT_PKCS11_KEY_ID_SIZE` (default `4`): this is the size, in bytes, of + the key ID. +- `ENCRYPT_PKCS11_MECHANISM` (default `0x00001086UL`, i.e. AES-CTR): this is + the numeric ID of the PKCS#11 mechanism to be used for encryption. Currently + only AES-CTR is supported. The list of IDs can be found in the [appendix of + the PKCS#11 mechanism specification](https://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/cs01/pkcs11-curr-v2.40-cs01.html#_Toc228894920), + while the list of IDs supported by wolfPKCS11 is set in the [pkcs11.h](https://github.com/wolfSSL/wolfPKCS11/blob/master/wolfpkcs11/pkcs11.h) + header file. +- `ENCRYPT_PKCS11_BLOCK_SIZE` (default `16`, for AES-CTR) and + `ENCRYPT_PKCS11_NONCE_SIZE` (default `16`, for AES-CTR) should be set in case + you set `ENCRYPT_PKCS11_MECHANISM` to something other than the default. ### Signing and encrypting the update bundle with ChaCha20-256 diff --git a/include/encrypt.h b/include/encrypt.h index 231ae9dc30..6515b296cd 100644 --- a/include/encrypt.h +++ b/include/encrypt.h @@ -63,6 +63,21 @@ extern Aes aes_dec, aes_enc; int aes_init(void); void aes_set_iv(uint8_t *nonce, uint32_t address); + +#elif defined(ENCRYPT_PKCS11) +#include "wolfboot/wcs_pkcs11.h" + +int pkcs11_crypto_init(void); +void pkcs11_crypto_set_iv(uint8_t *nonce, uint32_t iv_ctr); +int pkcs11_crypto_encrypt(uint8_t *out, uint8_t *in, size_t size); +int pkcs11_crypto_decrypt(uint8_t *out, uint8_t *in, size_t size); +void pkcs11_crypto_deinit(void); + +#define crypto_init() pkcs11_crypto_init() +#define crypto_encrypt(eb,b,sz) pkcs11_crypto_encrypt(eb, b, sz) +#define crypto_decrypt(db,b,sz) pkcs11_crypto_decrypt(db, b, sz) +#define crypto_set_iv(n,a) pkcs11_crypto_set_iv(n, a) + #endif /* ENCRYPT_WITH_CHACHA */ /* external flash encryption read/write functions */ diff --git a/include/user_settings.h b/include/user_settings.h index 9a82b62922..ca34d1fc6e 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -350,11 +350,15 @@ extern int tolower(int c); # define WOLFBOOT_SECURE_PKCS11 # define WOLFPKCS11_USER_SETTINGS # define WOLFPKCS11_NO_TIME +#ifndef WOLFSSL_AES_COUNTER # define WOLFSSL_AES_COUNTER +#endif +# define HAVE_AESCTR +#ifndef WOLFSSL_AES_DIRECT # define WOLFSSL_AES_DIRECT +#endif # define WOLFSSL_AES_GCM # define GCM_TABLE_4BIT -# define ENCRYPT_WITH_AES128 # define WOLFSSL_AES_128 # define HAVE_SCRYPT # define HAVE_AESGCM diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index eb57dc79d3..b92aced7f8 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -514,6 +514,11 @@ int wolfBoot_get_partition_state(uint8_t part, uint8_t *st); #define ENCRYPT_BLOCK_SIZE 16 #define ENCRYPT_KEY_SIZE 32 /* AES256 */ #define ENCRYPT_NONCE_SIZE 16 /* AES IV size */ +#elif defined(ENCRYPT_PKCS11) + #define ENCRYPT_BLOCK_SIZE ENCRYPT_PKCS11_BLOCK_SIZE + /* In this case, the key ID is stored in flash rather than the key itself */ + #define ENCRYPT_KEY_SIZE ENCRYPT_PKCS11_KEY_ID_SIZE + #define ENCRYPT_NONCE_SIZE ENCRYPT_PKCS11_NONCE_SIZE #else # error "Encryption ON, but no encryption algorithm selected." #endif diff --git a/options.mk b/options.mk index 75d5e5ec20..6af4fa668e 100644 --- a/options.mk +++ b/options.mk @@ -530,19 +530,37 @@ endif ifeq ($(ENCRYPT),1) CFLAGS+=-D"EXT_ENCRYPTED=1" - ifeq ($(ENCRYPT_WITH_AES128),1) - CFLAGS+=-DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT - CFLAGS+=-DENCRYPT_WITH_AES128 -DWOLFSSL_AES_128 - WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/aes.o + ifeq ($(ENCRYPT_PKCS11),1) + CFLAGS+=-DENCRYPT_PKCS11 -D'ENCRYPT_PKCS11_PIN=$(ENCRYPT_PKCS11_PIN)' + ifeq ($(ENCRYPT_PKCS11_KEY_ID_SIZE),) + ENCRYPT_PKCS11_KEY_ID_SIZE=4 + endif + CFLAGS+=-DENCRYPT_PKCS11_KEY_ID_SIZE=$(ENCRYPT_PKCS11_KEY_ID_SIZE) + ifeq ($(ENCRYPT_PKCS11_MECHANISM),) + # No mechanism defined; assume AES-CTR + CFLAGS+=-DENCRYPT_PKCS11_MECHANISM=0x00001086UL + CFLAGS+=-DENCRYPT_PKCS11_BLOCK_SIZE=16 + CFLAGS+=-DENCRYPT_PKCS11_NONCE_SIZE=16 + else + CFLAGS+=-DENCRYPT_PKCS11_MECHANISM=$(ENCRYPT_PKCS11_MECHANISM) + CFLAGS+=-DENCRYPT_PKCS11_BLOCK_SIZE=$(ENCRYPT_PKCS11_BLOCK_SIZE) + CFLAGS+=-DENCRYPT_PKCS11_NONCE_SIZE=$(ENCRYPT_PKCS11_NONCE_SIZE) + endif else - ifeq ($(ENCRYPT_WITH_AES256),1) + ifeq ($(ENCRYPT_WITH_AES128),1) CFLAGS+=-DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT - CFLAGS+=-DENCRYPT_WITH_AES256 -DWOLFSSL_AES_256 + CFLAGS+=-DENCRYPT_WITH_AES128 -DWOLFSSL_AES_128 WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/aes.o else - ENCRYPT_WITH_CHACHA=1 - WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/chacha.o - CFLAGS+=-DENCRYPT_WITH_CHACHA -DHAVE_CHACHA + ifeq ($(ENCRYPT_WITH_AES256),1) + CFLAGS+=-DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT + CFLAGS+=-DENCRYPT_WITH_AES256 -DWOLFSSL_AES_256 + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/aes.o + else + ENCRYPT_WITH_CHACHA=1 + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/chacha.o + CFLAGS+=-DENCRYPT_WITH_CHACHA -DHAVE_CHACHA + endif endif endif endif @@ -665,7 +683,7 @@ ifeq ($(WOLFCRYPT_TZ_PKCS11),1) $(WOLFBOOT_LIB_WOLFPKCS11)/src/slot.o \ $(WOLFBOOT_LIB_WOLFPKCS11)/src/wolfpkcs11.o STACK_USAGE=16688 - ifneq ($(ENCRYPT),1) + ifeq ($(ENCRYPT_WITH_AES128)$(ENCRYPT_WITH_AES256),) WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/aes.o endif ifeq ($(findstring RSA,$(SIGN)),) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 409b17852b..fd63e89512 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -1395,7 +1395,8 @@ void RAMFUNCTION wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counte { #if defined(ENCRYPT_WITH_CHACHA) crypto_set_iv((uint8_t *)nonce, iv_counter + encrypt_iv_offset); -#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256) +#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256) || \ + defined(ENCRYPT_PKCS11) uint8_t local_nonce[ENCRYPT_NONCE_SIZE]; XMEMCPY(local_nonce, nonce, ENCRYPT_NONCE_SIZE); crypto_set_iv(local_nonce, iv_counter + encrypt_iv_offset); @@ -1423,8 +1424,10 @@ static int RAMFUNCTION hal_set_key(const uint8_t *k, const uint8_t *nonce) #else uintptr_t addr, addr_align, addr_off; int ret = 0; - int sel_sec = 0; uint32_t trailer_relative_off = 4; +#ifdef NVM_FLASH_WRITEONCE + int sel_sec = 0; +#endif #if !defined(WOLFBOOT_SMALL_STACK) && !defined(NVM_FLASH_WRITEONCE) && \ !defined(WOLFBOOT_ENCRYPT_CACHE) uint8_t ENCRYPT_CACHE[NVM_CACHE_SIZE] XALIGNED_STACK(32); @@ -1532,8 +1535,8 @@ int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce) #else uint8_t *mem = (uint8_t *)(ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS); - int sel_sec = 0; #ifdef NVM_FLASH_WRITEONCE + int sel_sec = 0; sel_sec = nvm_select_fresh_sector(PART_BOOT); mem -= (sel_sec * WOLFBOOT_SECTOR_SIZE); #endif @@ -1562,9 +1565,8 @@ int RAMFUNCTION wolfBoot_erase_encrypt_key(void) uint8_t ff[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE]; uint8_t *mem = (uint8_t *)ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS; - int sel_sec = 0; #ifdef NVM_FLASH_WRITEONCE - sel_sec = nvm_select_fresh_sector(PART_BOOT); + int sel_sec = nvm_select_fresh_sector(PART_BOOT); mem -= (sel_sec * WOLFBOOT_SECTOR_SIZE); #endif XMEMSET(ff, FLASH_BYTE_ERASED, ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE); @@ -1742,6 +1744,236 @@ void aes_set_iv(uint8_t *nonce, uint32_t iv_ctr) wc_AesSetIV(&aes_dec, (byte *)iv_buf); } +#elif defined(ENCRYPT_PKCS11) + +static CK_FUNCTION_LIST *pkcs11_function_list; +static CK_SESSION_HANDLE pkcs11_session; +static uint8_t pkcs11_pin[] = ENCRYPT_PKCS11_PIN; +static CK_OBJECT_HANDLE pkcs11_key_handle; +static int pkcs11_enc_initialized = 0, pkcs11_dec_initialized = 0; +#if ENCRYPT_PKCS11_MECHANISM == CKM_AES_CTR +static CK_AES_CTR_PARAMS pkcs11_params; +#endif + +int pkcs11_crypto_init(void) +{ + CK_RV ret = 0; + uint8_t *key_id; + uint8_t *stored_nonce; + CK_OBJECT_CLASS class = CKO_SECRET_KEY; + CK_ATTRIBUTE search_attr[] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_ID, NULL, 0 }, + }; + CK_ULONG search_attr_count = sizeof(search_attr) / sizeof(*search_attr); + CK_ULONG obj_count; + int session_opened = 0, logged_in = 0; + + if (encrypt_initialized) + return 0; + + ret = C_GetFunctionList(&pkcs11_function_list); + + if (ret == CKR_OK) { + +#if defined(MMU) || defined(UNIT_TEST) + key_id = ENCRYPT_KEY; +#else + key_id = (uint8_t*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + + ENCRYPT_TMP_SECRET_OFFSET); +#endif + +#ifdef NVM_FLASH_WRITEONCE + key_id -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT); +#endif + stored_nonce = key_id + ENCRYPT_KEY_SIZE; + + search_attr[1].pValue = key_id; + search_attr[1].ulValueLen = ENCRYPT_PKCS11_KEY_ID_SIZE; + + /* Ensure TRNG is initialized, in case we're being called early */ + hal_trng_init(); + + ret = pkcs11_function_list->C_Initialize(NULL); + } + + if (ret == CKR_OK) { + ret = pkcs11_function_list->C_OpenSession(1, + CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, + &pkcs11_session); + session_opened = 1; + } + + if (ret == CKR_OK) { + ret = pkcs11_function_list->C_Login(pkcs11_session, CKU_USER, + pkcs11_pin, sizeof(pkcs11_pin) - 1); + logged_in = 1; + } + + if (ret == CKR_OK) { + /* Retrieve AES key by CKA_ID */ + ret = pkcs11_function_list->C_FindObjectsInit(pkcs11_session, + search_attr, search_attr_count); + } + + if (ret == CKR_OK) { + ret = pkcs11_function_list->C_FindObjects(pkcs11_session, + &pkcs11_key_handle, 1, &obj_count); + } + + if (ret == CKR_OK && obj_count != 1) { + ret = -1; + } + + if (ret == CKR_OK) { + ret = pkcs11_function_list->C_FindObjectsFinal(pkcs11_session); + } + + if (ret == CKR_OK) { + XMEMCPY(encrypt_iv_nonce, stored_nonce, ENCRYPT_PKCS11_NONCE_SIZE); + encrypt_initialized = 1; + } + + if (ret != CKR_OK) { + if (logged_in) { + pkcs11_function_list->C_Logout(pkcs11_session); + } + if (session_opened) { + pkcs11_function_list->C_CloseSession(pkcs11_session); + } + } + + return ret; +} + +void pkcs11_crypto_set_iv(uint8_t *nonce, uint32_t iv_ctr) +{ + CK_RV ret; + uint8_t buf[ENCRYPT_BLOCK_SIZE]; + CK_ULONG buf_len = sizeof(buf); + + if (pkcs11_enc_initialized) { + ret = pkcs11_function_list->C_EncryptFinal(pkcs11_session, buf, + &buf_len); + if (ret != CKR_OK) { + return; + } + pkcs11_enc_initialized = 0; + } + else if (pkcs11_dec_initialized) { + ret = pkcs11_function_list->C_DecryptFinal(pkcs11_session, buf, + &buf_len); + if (ret != CKR_OK) { + return; + } + pkcs11_dec_initialized = 0; + } + +#if ENCRYPT_PKCS11_MECHANISM == CKM_AES_CTR + { + uint32_t *cb_words = (uint32_t *)pkcs11_params.cb; + int i; + XMEMCPY(cb_words, nonce, ENCRYPT_NONCE_SIZE); +#ifndef BIG_ENDIAN_ORDER + for (i = 0; i < 4; i++) { + cb_words[i] = wb_reverse_word32(cb_words[i]); + } +#endif + cb_words[3] += iv_ctr; + if (cb_words[3] < iv_ctr) { /* overflow */ + for (i = 2; i >= 0; i--) { + cb_words[i]++; + if (cb_words[i] != 0) + break; + } + } +#ifndef BIG_ENDIAN_ORDER + for (i = 0; i < 4; i++) { + cb_words[i] = wb_reverse_word32(cb_words[i]); + } +#endif + + pkcs11_params.ulCounterBits = 32; + } +#endif /* ENCRYPT_PKCS11_MECHANISM */ +} + +int pkcs11_crypto_encrypt(uint8_t *out, uint8_t *in, size_t size) +{ + CK_RV ret; + CK_ULONG encrypted_len; + + if (pkcs11_dec_initialized) + return -1; + + if (!pkcs11_enc_initialized) { + CK_MECHANISM mech; + + mech.mechanism = ENCRYPT_PKCS11_MECHANISM; + mech.pParameter = &pkcs11_params; + mech.ulParameterLen = sizeof(pkcs11_params); + + ret = pkcs11_function_list->C_EncryptInit(pkcs11_session, &mech, + pkcs11_key_handle); + if (ret != CKR_OK) { + return -1; + } + + pkcs11_enc_initialized = 1; + } + + encrypted_len = size; + ret = pkcs11_function_list->C_EncryptUpdate(pkcs11_session, in, size, out, + &encrypted_len); + if (ret != CKR_OK) { + return -1; + } + + return 0; +} + +int pkcs11_crypto_decrypt(uint8_t *out, uint8_t *in, size_t size) +{ + CK_RV ret; + CK_ULONG decrypted_len; + + if (pkcs11_enc_initialized) + return -1; + + if (!pkcs11_dec_initialized) { + CK_MECHANISM mech; + + mech.mechanism = ENCRYPT_PKCS11_MECHANISM; + mech.pParameter = &pkcs11_params; + mech.ulParameterLen = sizeof(pkcs11_params); + + ret = pkcs11_function_list->C_DecryptInit(pkcs11_session, &mech, + pkcs11_key_handle); + if (ret != CKR_OK) { + return -1; + } + + pkcs11_dec_initialized = 1; + } + + decrypted_len = size; + ret = pkcs11_function_list->C_DecryptUpdate(pkcs11_session, in, size, out, + &decrypted_len); + if (ret != CKR_OK) { + return -1; + } + + return 0; +} + +void pkcs11_crypto_deinit(void) +{ + if (encrypt_initialized) { + pkcs11_function_list->C_CloseSession(pkcs11_session); + encrypt_initialized = 0; + } +} + #endif /** diff --git a/src/update_flash.c b/src/update_flash.c index 2cb6915ca8..af9f1e83be 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -1168,6 +1168,10 @@ void RAMFUNCTION wolfBoot_start(void) #endif #endif +#ifdef SECURE_PKCS11 + WP11_Library_Init(); +#endif + bootRet = wolfBoot_get_partition_state(PART_BOOT, &bootState); updateRet = wolfBoot_get_partition_state(PART_UPDATE, &updateState); @@ -1265,8 +1269,8 @@ void RAMFUNCTION wolfBoot_start(void) wolfBoot_tpm2_deinit(); #endif -#ifdef SECURE_PKCS11 - WP11_Library_Init(); +#ifdef ENCRYPT_PKCS11 + pkcs11_crypto_deinit(); #endif #ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT From 09cdc041c551b4e430e9d26bea56e9b67739bfd2 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 24 Dec 2025 15:35:30 +0100 Subject: [PATCH 2/2] Fix cppcheck complaint --- src/libwolfboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index fd63e89512..e60cb41af2 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -1766,7 +1766,7 @@ int pkcs11_crypto_init(void) { CKA_ID, NULL, 0 }, }; CK_ULONG search_attr_count = sizeof(search_attr) / sizeof(*search_attr); - CK_ULONG obj_count; + CK_ULONG obj_count = 0; int session_opened = 0, logged_in = 0; if (encrypt_initialized)