Add PKCS11 backend for encrypted partitions

pull/658/head
Mattia Moffa 2025-12-24 04:54:13 +01:00 committed by Daniele Lacamera
parent aa39be21a3
commit f12d2f06b4
7 changed files with 326 additions and 18 deletions

View File

@ -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

View File

@ -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 */

View File

@ -353,11 +353,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

View File

@ -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

View File

@ -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)),)

View File

@ -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
/**

View File

@ -1172,6 +1172,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);
@ -1269,8 +1273,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