Refactoring of PKCS11 store module + unit tests

pull/481/head
Daniele Lacamera 2024-08-12 11:01:32 +02:00
parent 002dc8d415
commit 6737d7e7ad
8 changed files with 850 additions and 97 deletions

View File

@ -843,3 +843,12 @@ endif
ifeq ($(SIGN_ALG),ext_LMS)
SIGN_ALG=LMS
endif
ifneq ($(KEYVAULT_OBJ_SIZE),)
CFLAGS+=-DKEYVAULT_OBJ_SIZE=$(KEYVAULT_OBJ_SIZE)
endif
ifneq ($(KEYVAULT_MAX_ITEMS),)
CFLAGS+=-DKEYVAULT_MAX_ITEMS=$(KEYVAULT_MAX_ITEMS)
endif

View File

@ -1,6 +1,6 @@
/* pkcs11_store.c
*
* Copyright (C) 2023 wolfSSL Inc.
* Copyright (C) 2024 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
@ -20,7 +20,6 @@
*/
#include <stdint.h>
#include <string.h>
@ -34,14 +33,13 @@
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/types.h>
extern uint32_t *_flash_keyvault; /* From linker script: origin of vault flash */
extern uint32_t *_flash_keyvault_size; /* From linker script: size of vault */
#ifndef KEYVAULT_OBJ_SIZE
#define KEYVAULT_OBJ_SIZE 0x1000 /* 4KB per object */
#endif
extern unsigned int _start_heap; /* From linker script: heap memory */
extern unsigned int _heap_size; /* From linker script: heap limit */
#define KEYVAULT_OBJ_SIZE 0x1000 /* 4KB per object */
#define KEYVAULT_MAX_ITEMS 0x18 /* Total memory: 0x18000, 24 items */
#ifndef KEYVAULT_MAX_ITEMS
#define KEYVAULT_MAX_ITEMS 0x17 /* Total memory: 0x18000, 22 items + 2 sector overhead */
#endif
/* Internal errors from wolfPKCS11 */
#define PIN_INVALID_E -1
@ -55,11 +53,16 @@ extern unsigned int _heap_size; /* From linker script: heap limit */
#define LOGGED_IN_E -9
#define OBJ_COUNT_E -10
#ifndef UNIT_TEST
extern uint32_t *_flash_keyvault; /* From linker script: origin of vault flash */
static uint8_t *vault_base = (uint8_t *)&_flash_keyvault;
static int vault_idx = -1;
/* Back-end for malloc, used by wolfPKCS11 */
extern unsigned int _start_heap; /* From linker script: heap memory */
extern unsigned int _heap_size; /* From linker script: heap limit */
/* Back-end for malloc, used for token handling */
void * _sbrk(unsigned int incr)
{
static unsigned char *heap = (unsigned char *)&_start_heap;
@ -78,133 +81,452 @@ void * _sbrk(unsigned int incr)
}
return old_heap;
}
#endif
static int vault_idx = -1;
struct obj_hdr
{
uint32_t token_id;
uint32_t object_id;
int type;
uint32_t off;
int32_t type;
uint32_t pos;
uint32_t size;
uint32_t __pad[3];
};
#define STORE_PRIV_HDR_SIZE 16
#define STORE_PRIV_HDR_SIZE 0x20
#define STORE_PRIV_HDR_OFFSET 0x80
#define PKCS11_INVALID_ID 0xFFFFFFFF
struct store_object
#define BITMAP_OFFSET (4)
#define BITMAP_SIZE (KEYVAULT_MAX_ITEMS / 8 + 1)
#if (BITMAP_SIZE > (STORE_PRIV_HDR_OFFSET - 4))
#error Too many keyvault items
#endif
/* This spells "PKCS" */
#ifndef BIG_ENDIAN_ORDER
#define VAULT_HEADER_MAGIC 0x53434B50
#else
#define VAULT_HEADER_MAGIC 0x504B4353
#endif
#define MAX_OPEN_STORES 16
struct store_handle {
uint32_t flags;
uint32_t pos;
void *buffer;
struct obj_hdr *hdr;
uint32_t in_buffer_offset;
};
#define STORE_FLAGS_OPEN (1 << 0)
#define STORE_FLAGS_READONLY (1 << 1)
static struct store_handle openstores_handles[MAX_OPEN_STORES] = {};
static uint8_t cached_sector[WOLFBOOT_SECTOR_SIZE];
static void bitmap_put(uint32_t pos, int val)
{
struct obj_hdr hdr;
int vault_idx;
int read;
};
uint32_t octet = pos / 8;
uint32_t bit = pos % 8;
uint8_t *bitmap = cached_sector + sizeof(uint32_t);
static struct store_object *vault_descriptors[KEYVAULT_MAX_ITEMS];
if (val != 0) {
bitmap[octet] |= (1 << bit);
} else {
bitmap[octet] &= ~(1 << bit);
}
}
static int bitmap_get(uint32_t pos)
{
uint32_t octet = pos / 8;
uint32_t bit = pos % 8;
uint8_t *bitmap = vault_base + sizeof(uint32_t);
return (bitmap[octet] & (1 << bit)) >> bit;
}
static int bitmap_find_free_pos(void)
{
int i, j;
for (i = 0; i < KEYVAULT_MAX_ITEMS; i++) {
if (bitmap_get(i) == 0)
return i;
}
return -1;
}
/* A table with nodes is stored at the beginning of the keyvault
* - 4 B: Magic (spells "PKCS" when the vault is initialized)
* - N B: bitmap (N = KEYVAULT_MAX_ITEMS / 8 + 1)
*
* At byte 0x80:
* - Start of the obj hdr structures array
*/
#define NODES_TABLE ( (struct obj_hdr *)(vault_base + STORE_PRIV_HDR_OFFSET) )
/* A backup sector immediately after the header sector */
#define BACKUP_SECTOR_ADDRESS (vault_base + WOLFBOOT_SECTOR_SIZE)
static void cache_commit(uint32_t offset)
{
hal_flash_unlock();
/* Write backup sector first */
hal_flash_erase((uint32_t)BACKUP_SECTOR_ADDRESS, WOLFBOOT_SECTOR_SIZE);
hal_flash_write((uint32_t)BACKUP_SECTOR_ADDRESS, cached_sector, WOLFBOOT_SECTOR_SIZE);
/* Erase + write actual destination sector */
hal_flash_erase((uint32_t)vault_base + offset, WOLFBOOT_SECTOR_SIZE);
hal_flash_write((uint32_t)vault_base + offset, cached_sector, WOLFBOOT_SECTOR_SIZE);
hal_flash_lock();
}
static void restore_backup(uint32_t offset)
{
hal_flash_unlock();
/* Erase + copy from backup */
hal_flash_erase((uint32_t)vault_base + offset, WOLFBOOT_SECTOR_SIZE);
hal_flash_write((uint32_t)vault_base + offset, BACKUP_SECTOR_ADDRESS,
WOLFBOOT_SECTOR_SIZE);
hal_flash_lock();
}
static void check_vault(void)
{
uint32_t *magic = (uint32_t *)vault_base;
uint32_t total_vault_size = KEYVAULT_MAX_ITEMS * KEYVAULT_OBJ_SIZE;
if ((total_vault_size % WOLFBOOT_SECTOR_SIZE) != 0)
total_vault_size = (total_vault_size / WOLFBOOT_SECTOR_SIZE) * WOLFBOOT_SECTOR_SIZE + WOLFBOOT_SECTOR_SIZE;
if (*magic != VAULT_HEADER_MAGIC) {
uint32_t *magic = (uint32_t *)BACKUP_SECTOR_ADDRESS;
if (*magic == VAULT_HEADER_MAGIC) {
restore_backup(0);
return;
}
memset(cached_sector, 0xFF, WOLFBOOT_SECTOR_SIZE);
magic = (uint32_t *)cached_sector;
*magic = VAULT_HEADER_MAGIC;
memset(cached_sector + sizeof(uint32_t), 0x00, BITMAP_SIZE);
cache_commit(0);
hal_flash_unlock();
hal_flash_erase((uint32_t)vault_base + WOLFBOOT_SECTOR_SIZE * 2, total_vault_size);
hal_flash_lock();
}
}
static void delete_object(int32_t type, uint32_t tok_id, uint32_t obj_id)
{
struct obj_hdr *hdr = (struct obj_hdr *)cached_sector;
check_vault();
memcpy(cached_sector, vault_base, WOLFBOOT_SECTOR_SIZE);
while ((uintptr_t)hdr < ((uintptr_t)cached_sector + WOLFBOOT_SECTOR_SIZE)) {
if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id) &&
(hdr->type == type)) {
hdr->token_id = PKCS11_INVALID_ID;
hdr->object_id = PKCS11_INVALID_ID;
bitmap_put(hdr->pos, 0);
cache_commit(0);
return;
}
hdr++;
}
}
/* Returns a pointer to the selected object in flash.
* NULL is OK here as error return value, even if the keystore
* started at physical 0x0000 0000, the buffers are stored from sector
* 2 onwards.
*/
static uint8_t *find_object_buffer(int32_t type, uint32_t tok_id, uint32_t obj_id)
{
struct obj_hdr *hdr = NODES_TABLE;
uint32_t *tok_obj_stored = NULL;
while ((uint32_t)hdr < ((uint32_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) {
if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id)
&& (hdr->type == type)) {
tok_obj_stored = (uint32_t *) (vault_base + (2 * WOLFBOOT_SECTOR_SIZE) + (hdr->pos * KEYVAULT_OBJ_SIZE));
if ((tok_obj_stored[0] != tok_id) || (tok_obj_stored[1] != obj_id)) {
/* Id's don't match. Try backup sector. */
uint32_t in_sector_off = (hdr->pos * KEYVAULT_OBJ_SIZE) %
WOLFBOOT_SECTOR_SIZE;
uint32_t sector_base = hdr->pos * KEYVAULT_OBJ_SIZE +
2 * WOLFBOOT_SECTOR_SIZE - in_sector_off;
tok_obj_stored = (uint32_t *)((BACKUP_SECTOR_ADDRESS + in_sector_off));
if ((tok_obj_stored[0] == tok_id) && (tok_obj_stored[1] == obj_id)) {
/* Found backup! restoring... */
restore_backup(sector_base);
} else {
delete_object(type, tok_id, obj_id);
return NULL; /* Cannot recover object payload */
}
}
/* Object is now OK */
return vault_base + 2 * WOLFBOOT_SECTOR_SIZE + hdr->pos * KEYVAULT_OBJ_SIZE;
}
hdr++;
}
return NULL; /* object not found */
}
static struct obj_hdr *find_object_header(int32_t type, uint32_t tok_id,
uint32_t obj_id)
{
struct obj_hdr *hdr = NODES_TABLE;
uint32_t *tok_obj_stored = NULL;
while ((uint32_t)hdr < ((uint32_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) {
if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id)
&& (hdr->type == type)) {
return hdr;
}
hdr++;
}
return NULL;
}
static struct obj_hdr *create_object(int32_t type, uint32_t tok_id, uint32_t obj_id)
{
struct obj_hdr *hdr = NULL;
uint32_t *tok_obj_id;
/* Refuse to create an object that's already in store */
if (find_object_buffer(type, tok_id, obj_id) != NULL) {
return NULL;
}
/* Caching sector 0 */
memcpy(cached_sector, vault_base , WOLFBOOT_SECTOR_SIZE);
hdr = (struct obj_hdr *)(cached_sector + STORE_PRIV_HDR_OFFSET);
while ((uint32_t)hdr < ((uint32_t)cached_sector + WOLFBOOT_SECTOR_SIZE)) {
if (hdr->token_id == PKCS11_INVALID_ID) {
uint32_t sector_base, in_sector_off;
int pos = bitmap_find_free_pos();
if (pos < 0) {
return NULL;
}
hdr->pos = (unsigned)pos;
in_sector_off = (hdr->pos * KEYVAULT_OBJ_SIZE) %
WOLFBOOT_SECTOR_SIZE;
sector_base = hdr->pos * KEYVAULT_OBJ_SIZE +
2 * WOLFBOOT_SECTOR_SIZE - in_sector_off;
/* Claim the spot in the table */
hdr->token_id = tok_id;
hdr->object_id = obj_id;
hdr->type = type;
/* Set vault initial size to eight bytes (this includes the
* tok/obj id at the beginning of the buffer, before the
* payload). When an object is opened, the initial 'in_buffer_offset'
* is set to 8 as well.
*/
hdr->size = 2 * sizeof(uint32_t);
/* Set the bit to claim the position in flash */
bitmap_put(hdr->pos, 1);
cache_commit(0);
/* Mark the beginning of the object in the sector,
* write the tok/obj ids
*/
memcpy(cached_sector, vault_base + sector_base,
WOLFBOOT_SECTOR_SIZE);
tok_obj_id = (uint32_t *)(cached_sector + in_sector_off);
tok_obj_id[0] = tok_id;
tok_obj_id[1] = obj_id;
cache_commit(sector_base);
/* Return the address of the header in flash */
return (struct obj_hdr *)(vault_base + ((uint8_t *)hdr - (uint8_t *)cached_sector));
}
hdr++;
}
return NULL; /* No space left in the nodes table */
}
static void update_store_size(struct obj_hdr *hdr, uint32_t size)
{
uint32_t off;
struct obj_hdr *hdr_mem;
if (((uint8_t *)hdr) < vault_base ||
((uint8_t *)hdr > vault_base + WOLFBOOT_SECTOR_SIZE))
return;
check_vault();
off = (uint32_t)hdr - (uint32_t)vault_base;
memcpy(cached_sector, vault_base, WOLFBOOT_SECTOR_SIZE);
hdr_mem = (struct obj_hdr *)(cached_sector + off);
hdr_mem->size = size;
cache_commit(0);
}
/* Find a free handle in openstores_handles[] array
* to manage the interaction with the API.
*
* A maximum of MAX_OPEN_STORES objects can be opened
* at the same time.
*/
static struct store_handle *find_free_handle(void)
{
int i;
for (i = 0; i < MAX_OPEN_STORES; i++) {
if ((openstores_handles[i].flags & STORE_FLAGS_OPEN) == 0)
return &openstores_handles[i];
}
return NULL;
}
int wolfPKCS11_Store_Open(int type, CK_ULONG id1, CK_ULONG id2, int read,
void** store)
{
unsigned int i;
unsigned int found = 0;
struct obj_hdr *hdr;
struct store_object *obj;
struct store_handle *handle;
uint8_t *buf;
struct obj_hdr *hdr = NULL;
for (i = 1; i < KEYVAULT_MAX_ITEMS; i++) {
hdr = (struct obj_hdr*)(vault_base + i * KEYVAULT_OBJ_SIZE);
if ((type == hdr->type) && (id1 == hdr->token_id) &&
(id2 == hdr->object_id)) {
found = i;
break;
}
/* Check if there is one handle available to open the slot */
handle = find_free_handle();
if (!handle) {
*store = NULL;
return SESSION_COUNT_E;
}
if ((!found) && read) {
/* Check if the target object exists */
check_vault();
buf = find_object_buffer(type, id1, id2);
if ((buf == NULL) && read) {
*store = NULL;
return NOT_AVAILABLE_E;
} else if (found) {
*store = vault_descriptors[found];
obj = vault_descriptors[found];
memcpy(&obj->hdr, vault_base + found * KEYVAULT_OBJ_SIZE, sizeof(struct obj_hdr));
obj->vault_idx = found;
obj->read = read;
} else if ((!found) && (!read)) {
if (vault_idx++ >= KEYVAULT_MAX_ITEMS) {
vault_idx--;
}
if ((buf == NULL) && (!read)) {
handle->hdr = create_object(type, id1, id2);
if (handle->hdr == NULL) {
*store = NULL;
return FIND_FULL_E;
}
obj = XMALLOC(sizeof(struct store_object), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (!obj)
buf = find_object_buffer(type, id1, id2);
if (!buf) {
*store = NULL;
return NOT_AVAILABLE_E;
vault_descriptors[vault_idx] = obj;
hdr = (struct obj_hdr *)obj;
obj->vault_idx = vault_idx;
obj->hdr.type = type;
obj->hdr.token_id = id1;
obj->hdr.object_id = id2;
obj->hdr.size = 0;
obj->read = 0;
hal_flash_unlock();
hal_flash_erase((uint32_t)(vault_base + vault_idx * KEYVAULT_OBJ_SIZE),
KEYVAULT_OBJ_SIZE);
hal_flash_write((uint32_t)(vault_base + vault_idx * KEYVAULT_OBJ_SIZE), (void *)obj,
sizeof(struct obj_hdr));
hal_flash_lock();
*store = obj;
}
} else { /* buf != NULL, readonly */
handle->hdr = find_object_header(type, id1, id2);
if (!handle->hdr) {
*store = NULL;
return NOT_AVAILABLE_E;
}
}
hdr->off = 0;
/* Set the position of the buffer in the handle */
handle->buffer = buf;
handle->pos = (((uint32_t)buf) - (uint32_t)vault_base) / KEYVAULT_OBJ_SIZE;
/* Set the 'open' flag */
handle->flags |= STORE_FLAGS_OPEN;
/* Set the 'readonly' flag in this handle if open with 'r' */
if (read)
handle->flags |= STORE_FLAGS_READONLY;
else {
handle->flags &= ~STORE_FLAGS_READONLY;
/* Truncate the slot when opening in write mode */
update_store_size(handle->hdr, 2 * sizeof(uint32_t));
}
/* Set start of the buffer after the tok/obj id fields */
handle->in_buffer_offset = (2 * sizeof(uint32_t));
*store = handle;
return 0;
}
void wolfPKCS11_Store_Close(void* store)
{
struct store_object *obj = store;
vault_descriptors[obj->vault_idx] = NULL;
XFREE(obj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
struct store_handle *handle = store;
/* This removes all flags (including STORE_FLAGS_OPEN) */
handle->flags = 0;
handle->hdr = NULL;
}
int wolfPKCS11_Store_Read(void* store, unsigned char* buffer, int len)
{
struct store_object *obj = store;
if ((uint32_t)len + obj->hdr.off > obj->hdr.size) {
len = obj->hdr.size - obj->hdr.off;
}
struct store_handle *handle = store;
uint32_t *tok_obj_id;
uint32_t obj_size = 0;
if ((handle == NULL) || (handle->hdr == NULL) || (handle->buffer == NULL))
return -1;
tok_obj_id = (uint32_t *)handle->buffer;
obj_size = handle->hdr->size;
if (obj_size > KEYVAULT_OBJ_SIZE)
return -1;
if (handle->in_buffer_offset >= obj_size)
return 0; /* "EOF" */
/* Truncate len to actual available bytes */
if (handle->in_buffer_offset + len > obj_size)
len = (obj_size - handle->in_buffer_offset);
if (len > 0) {
memcpy(buffer, vault_base + obj->vault_idx * KEYVAULT_OBJ_SIZE +
STORE_PRIV_HDR_SIZE + obj->hdr.off, len);
obj->hdr.off += len;
memcpy(buffer, (uint8_t *)(handle->buffer) + handle->in_buffer_offset, len);
handle->in_buffer_offset += len;
}
return len;
}
int wolfPKCS11_Store_Write(void* store, unsigned char* buffer, int len)
{
struct store_object *obj = store;
int pos = 0;
if (len + obj->hdr.off > (KEYVAULT_OBJ_SIZE - STORE_PRIV_HDR_SIZE)) {
return -1;
}
if (obj->read)
return -1;
if (obj->vault_idx > KEYVAULT_MAX_ITEMS)
return -1;
obj->hdr.size += len;
hal_flash_unlock();
if (obj->hdr.off == 0)
hal_flash_erase((uint32_t)(vault_base + obj->vault_idx * KEYVAULT_OBJ_SIZE),
KEYVAULT_OBJ_SIZE);
struct store_handle *handle = store;
uint32_t obj_size = 0;
uint32_t in_sector_offset = 0;
uint32_t in_sector_len = 0;
uint32_t sector_base = 0;
int written = 0;
hal_flash_write((uint32_t)(vault_base + obj->vault_idx * KEYVAULT_OBJ_SIZE),
(void *)obj, sizeof(struct obj_hdr));
while (pos < len) {
uint32_t base = (uint32_t)(vault_base +
obj->vault_idx * KEYVAULT_OBJ_SIZE);
uint32_t sz = len;
if (sz > WOLFBOOT_SECTOR_SIZE) {
sz = WOLFBOOT_SECTOR_SIZE;
}
hal_flash_write(base + STORE_PRIV_HDR_SIZE + pos, buffer + pos + obj->hdr.off, sz);
pos += sz;
if ((handle == NULL) || (handle->hdr == NULL) || (handle->buffer == NULL))
return -1;
if ((handle->flags & STORE_FLAGS_READONLY) != 0)
return -1;
obj_size = handle->hdr->size;
if (obj_size > KEYVAULT_OBJ_SIZE)
return -1;
if (len + handle->in_buffer_offset > KEYVAULT_OBJ_SIZE)
len = KEYVAULT_OBJ_SIZE - handle->in_buffer_offset;
if (len < 0)
return -1;
while (written < len) {
in_sector_offset = ((uint32_t)(handle->buffer) + handle->in_buffer_offset)
% WOLFBOOT_SECTOR_SIZE;
sector_base = (uint32_t)handle->buffer + handle->in_buffer_offset - in_sector_offset;
in_sector_len = WOLFBOOT_SECTOR_SIZE - in_sector_offset;
if (in_sector_len > (uint32_t)len)
in_sector_len = len;
/* Cache the corresponding sector */
memcpy(cached_sector, (void *)sector_base, WOLFBOOT_SECTOR_SIZE);
/* Write content into cache */
memcpy(cached_sector + in_sector_offset, buffer + written, in_sector_len);
/* Adjust in_buffer position for the handle accordingly */
handle->in_buffer_offset += in_sector_len;
written += in_sector_len;
/* Write sector to flash */
cache_commit((uint32_t)sector_base - (uint32_t)vault_base);
}
hal_flash_lock();
obj->hdr.off += len;
obj_size += written;
update_store_size(handle->hdr, obj_size);
return len;
}

View File

@ -102,4 +102,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
XMSS_PARAMS \
ELF BIG_ENDIAN \
NXP_CUSTOM_DCD NXP_CUSTOM_DCD_OBJS \
FLASH_OTP_KEYSTORE
FLASH_OTP_KEYSTORE \
KEYVAULT_OBJ_SIZE \
KEYVAULT_MAX_ITEMS

View File

@ -13,13 +13,14 @@ CFLAGS+=--coverage
LDFLAGS+=-fprofile-arcs
LDFLAGS+=-ftest-coverage
WOLFCRYPT=../../lib/wolfssl/
WOLFPKCS11=../../lib/wolfPKCS11/
TESTS:=unit-parser unit-extflash unit-aes128 unit-aes256 unit-chacha20 unit-pci \
unit-mock-state unit-sectorflags unit-image unit-nvm unit-nvm-flagshome \
unit-enc-nvm unit-enc-nvm-flagshome unit-delta unit-update-flash \
unit-update-ram
unit-update-ram unit-pkcs11_store
all: $(TESTS)
@ -62,6 +63,7 @@ unit-update-flash:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH
unit-update-ram:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \
-DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT \
-DPART_SWAP_EXT -DPART_BOOT_EXT -DWOLFBOOT_DUALBOOT -DNO_XIP
unit-pkcs11_store:CFLAGS+=-I$(WOLFPKCS11) -DMOCK_PARTITIONS -DMOCK_KEYVAULT -DSECURE_PKCS11
@ -124,6 +126,9 @@ unit-update-flash: ../../include/target.h unit-update-flash.c
unit-update-ram: ../../include/target.h unit-update-ram.c
gcc -o $@ unit-update-ram.c ../../src/image.c ../../lib/wolfssl/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS)
unit-pkcs11_store: ../../include/target.h unit-pkcs11_store.c
gcc -o $@ $(WOLFCRYPT_SRC) unit-pkcs11_store.c $(CFLAGS) $(WOLFCRYPT_CFLAGS) $(LDFLAGS)
%.o:%.c
gcc -c -o $@ $^ $(CFLAGS)

View File

@ -43,6 +43,7 @@
#else
#define WOLFBOOT_PARTITION_SIZE 0x8000
#endif
#define WOLFBOOT_KEYVAULT 0xCF000000
#else
#ifdef WOLFBOOT_FIXED_PARTITIONS

View File

@ -0,0 +1,118 @@
/*
* txt_filler.h
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
* This file contains excerpts from "La Divina Commedia" by Dante Alighieri,
* written in the early 14th century.
* The text of "La Divina Commedia" is in the public domain worldwide.
*
* Public Domain Notice:
* This work is free of known copyright restrictions.
*
*/
#ifndef DANTE_FILLER
#define DANTE_FILLER \
"Nel mezzo del cammin di nostra vita " \
"mi ritrovai per una selva oscura, " \
"ché la diritta via era smarrita. " \
" " \
"Ahi quanto a dir qual era è cosa dura " \
"esta selva selvaggia e aspra e forte " \
"che nel pensier rinova la paura! " \
" " \
"Tant è amara che poco è più morte; " \
"ma per trattar del ben chi vi trovai, " \
"dirò de laltre cose chi vho scorte. " \
" " \
"Io non so ben ridir com i vintrai, " \
"tant era pien di sonno a quel punto " \
"che la verace via abbandonai. " \
" " \
"Ma poi chi fui al piè dun colle giunto, " \
"là dove terminava quella valle " \
"che mavea di paura il cor compunto, " \
" " \
"guardai in alto e vidi le sue spalle " \
"vestite già de raggi del pianeta " \
"che mena dritto altrui per ogne calle. " \
" " \
"Allor fu la paura un poco queta, " \
"che nel lago del cor mera durata " \
"la notte chi passai con tanta pieta. " \
" " \
"E come quei che con lena affannata, " \
"uscito fuor del pelago a la riva, " \
"si volge a lacqua perigliosa e guata, " \
" " \
"così lanimo mio, chancor fuggiva, " \
"si volse a retro a rimirar lo passo " \
"che non lasciò già mai persona viva. " \
" " \
"Poi chèi posato un poco il corpo lasso, " \
"ripresi via per la piaggia diserta, " \
"sì che l piè fermo sempre era l più basso. " \
" " \
"Ed ecco, quasi al cominciar de lerta, " \
"una lonza leggera e presta molto, " \
"che di pel macolato era coverta; " \
" " \
"e non mi si partia dinanzi al volto, " \
"anzi mpediva tanto il mio cammino, " \
"chi fui per ritornar più volte vòlto. " \
" " \
"Temp era dal principio del mattino, " \
"e l sol montava n sù con quelle stelle " \
"cheran con lui quando lamor divino " \
" " \
"mosse di prima quelle cose belle; " \
"sì cha bene sperar mera cagione " \
"di quella fiera a la gaetta pelle " \
" " \
"lora del tempo e la dolce stagione; " \
"ma non sì che paura non mi desse " \
"la vista che mapparve dun leone. " \
" " \
"Questi parea che contra me venisse " \
"con la test alta e con rabbiosa fame, " \
"sì che parea che laere ne tremesse. " \
" " \
"Ed una lupa, che di tutte brame " \
"sembiava carca ne la sua magrezza, " \
"e molte genti fé già viver grame, " \
" " \
"questa mi porse tanto di gravezza " \
"con la paura chuscia di sua vista, " \
"chio perdei la speranza de laltezza. " \
" " \
"E qual è quei che volontieri acquista, " \
"e giugne l tempo che perder lo face, " \
"che n tutti suoi pensier piange e sattrista" \
" " \
"tal mi fece la bestia sanza pace, " \
"che, venendomi ncontro, a poco a poco " \
"mi ripigneva là dove l sol tace. " \
" " \
"Mentre chi rovinava in basso loco, " \
"dinanzi a li occhi mi si fu offerto " \
"chi per lungo silenzio parea fioco. " \
" " \
"Quando vidi costui nel gran diserto, " \
"«Miserere di me», gridai a lui, " \
"«qual che tu sii, od ombra od omo certo!». "
#endif

View File

@ -97,6 +97,7 @@ int hal_flash_erase(haladdr_t address, int len)
memset(address, 0xFF, len);
#ifdef MOCK_KEYVAULT
} else if ((address >= vault_base) && (address < vault_base + keyvault_size)) {
printf("Erasing vault from %p : %p bytes\n", address, len);
erased_vault++;
memset(address, 0xFF, len);
#endif

View File

@ -0,0 +1,294 @@
/* unit-pkcs11_store.c
*
* Unit test for PKCS11 storage module
*
*
* Copyright (C) 2024 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Option to enable sign tool debugging */
/* Must also define DEBUG_WOLFSSL in user_settings.h */
#define WOLFBOOT_HASH_SHA256
#define EXT_FLASH
#define PART_UPDATE_EXT
#define NVM_FLASH_WRITEONCE
#if defined(ENCRYPT_WITH_AES256) || defined(ENCRYPT_WITH_AES128)
#define WOLFSSL_AES_COUNTER
#define WOLFSSL_AES_DIRECT
#endif
#if defined(ENCRYPT_WITH_AES256)
#define WOLFSSL_AES_256
#endif
#if defined(ENCRYPT_WITH_CHACHA)
#define HAVE_CHACHA
#endif
#define ECC_TIMING_RESISTANT
#define WOLFSSL_USER_SETTINGS
#define UNIT_TEST
#define WOLFBOOT_SIGN_ECC256
#define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC256
#define __WOLFBOOT
#include <stdio.h>
#include <check.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define XMALLOC_OVERRIDE
#define XMALLOC(n,h,t) malloc(n)
#define XFREE(p,h,t) free(p)
#include "user_settings.h"
#include "wolfssl/wolfcrypt/sha.h"
#include "wolfboot/wolfboot.h"
#include "wolfpkcs11/pkcs11.h"
#include "hal.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MOCK_ADDRESS 0xCF000000
uint8_t *vault_base = (uint8_t *)MOCK_ADDRESS;
#include "unit-keystore.c"
#include "pkcs11_store.c"
const uint32_t keyvault_size = KEYVAULT_OBJ_SIZE * KEYVAULT_MAX_ITEMS + 2 * WOLFBOOT_SECTOR_SIZE;
#include "unit-mock-flash.c"
#include "txt_filler.h"
const char dante_filler[KEYVAULT_OBJ_SIZE] = DANTE_FILLER;
START_TEST (test_store_and_load_objs) {
CK_ULONG id_tok, id_obj;
int type;
int ret, readonly;
void *store = NULL;
const char secret1[] = "Everyone gets Friday off.";
const char secret2[] = "This is just a test string.";
const char short_string[] = "Short string";
char secret_rd[KEYVAULT_OBJ_SIZE];
type = DYNAMIC_TYPE_ECC;
id_tok = 1;
id_obj = 12;
readonly = 0;
ret = mmap_file("/tmp/wolfboot-unit-keyvault.bin", vault_base,
keyvault_size, NULL);
fail_if(ret != 0);
memset(vault_base, 0xEE, keyvault_size);
/* Open the vault, create the object */
fprintf(stderr, "Opening the vault\n");
printf("Flash Keyvault: %p\n", vault_base);
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to open the vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address");
fprintf(stderr, "open successful\n");
/* Test two subsequent writes */
ret = wolfPKCS11_Store_Write(store, secret1, strlen(secret1) + 1);
ck_assert_int_eq(ret, strlen(secret1) + 1);
ret = wolfPKCS11_Store_Write(store, secret2, strlen(secret2) + 1);
ck_assert_int_eq(ret, strlen(secret2) + 1);
wolfPKCS11_Store_Close(store);
printf("Closed vault. Reopening in RO mode\n");
/* Reopen for reading */
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault in read-only mode: %d", ret);
/* Read out the content */
ret = wolfPKCS11_Store_Read(store, secret_rd, 128);
fail_if(ret != strlen(secret1) + strlen(secret2) + 2);
fail_if(strcmp(secret1, secret_rd) != 0);
fail_if(strcmp(secret2, secret_rd + 1 + strlen(secret1)) != 0);
wolfPKCS11_Store_Close(store);
/* Create a second object with same Ids, different type*/
type = DYNAMIC_TYPE_RSA;
readonly = 0;
fprintf(stderr, "Opening the second vault\n");
printf("Flash Keyvault: %p\n", vault_base);
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to open the 2nd vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address for 2nd vault");
fprintf(stderr, "open 2 successful\n");
ret = wolfPKCS11_Store_Write(store, secret2, strlen(secret2) + 1);
wolfPKCS11_Store_Close(store);
/* Reopen for reading */
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault in read-only mode: %d", ret);
/* Read out the content */
ret = wolfPKCS11_Store_Read(store, secret_rd, 128);
fail_if(ret != strlen(secret2) + 1);
fail_if(strcmp(secret2, secret_rd) != 0);
wolfPKCS11_Store_Close(store);
/* Create more similar objects, different secret */
type = DYNAMIC_TYPE_RSA;
id_tok = 2;
id_obj = 22;
readonly = 0;
fprintf(stderr, "Creating one more vault\n");
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to create vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address for vault");
fprintf(stderr, "open 2 successful\n");
ret = wolfPKCS11_Store_Write(store, secret1, strlen(secret1) + 1);
id_tok = 3;
id_obj = 23;
readonly = 0;
fprintf(stderr, "Creating one more vault\n");
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to create vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address for vault");
fprintf(stderr, "open 2 successful\n");
ret = wolfPKCS11_Store_Write(store, secret1, strlen(secret1) + 1);
wolfPKCS11_Store_Close(store);
/* Reopen for reading */
id_tok = 1;
id_obj = 12;
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault in read-only mode: %d", ret);
/* Read out the content */
ret = wolfPKCS11_Store_Read(store, secret_rd, 128);
fail_if(ret != strlen(secret2) + 1);
fail_if(strcmp(secret2, secret_rd) != 0);
wolfPKCS11_Store_Close(store);
/* Open non-existing vaults */
id_tok = 5;
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret == 0, "Returned with success with invalid id_tok %d", id_tok);
id_tok = 2;
id_obj = 0;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret == 0, "Returned with success with invalid id_obj %d", id_obj);
type = 0xFF;
id_tok = 2;
id_obj = 23;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret == 0, "Returned with success with invalid type %d", type);
/* Test backup recovery for allocation table */
memset(vault_base, 0xEE, WOLFBOOT_SECTOR_SIZE);
type = DYNAMIC_TYPE_RSA;
id_tok = 1;
id_obj = 12;
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault recovering from alloc table backup: %d", ret);
/* Read out the content */
ret = wolfPKCS11_Store_Read(store, secret_rd, 128);
fail_if(ret != strlen(secret2) + 1);
fail_if(strcmp(secret2, secret_rd) != 0);
wolfPKCS11_Store_Close(store);
/* Test backup recovery for object sector */
printf("Test recovery sector...\n");
memcpy(vault_base + WOLFBOOT_SECTOR_SIZE, vault_base + 0x1800,
WOLFBOOT_SECTOR_SIZE);
memset(vault_base + 0x1800, 0xEE, WOLFBOOT_SECTOR_SIZE);
id_tok = 1;
id_obj = 12;
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault recovering from object sector backup: %d", ret);
/* Read out the content */
ret = wolfPKCS11_Store_Read(store, secret_rd, 128);
fail_if(ret != strlen(secret2) + 1);
fail_if(strcmp(secret2, secret_rd) != 0);
wolfPKCS11_Store_Close(store);
/* Test with very large payload */
type = DYNAMIC_TYPE_RSA;
id_tok = 3;
id_obj = 33;
readonly = 0;
fprintf(stderr, "Creating one BIG vault\n");
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to create vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address for vault");
fprintf(stderr, "open 3.33 successful\n");
ret = wolfPKCS11_Store_Write(store, dante_filler, strlen(dante_filler) + 1);
wolfPKCS11_Store_Close(store);
/* Reopen for reading */
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault in read-only mode: %d", ret);
/* Read out the content */
memset(secret_rd, 0, KEYVAULT_OBJ_SIZE);
ret = wolfPKCS11_Store_Read(store, secret_rd, KEYVAULT_OBJ_SIZE);
fail_if(ret != KEYVAULT_OBJ_SIZE - 8);
fail_if(strncmp(dante_filler, secret_rd, KEYVAULT_OBJ_SIZE - 8) != 0);
wolfPKCS11_Store_Close(store);
/* Reopen for writing, test truncate */
readonly = 0;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_unless(ret == 0, "Failed to create vault: %d", ret);
fail_if(store == NULL, "Did not receive a store address for vault");
fprintf(stderr, "open 3.33 successful\n");
ret = wolfPKCS11_Store_Write(store, short_string, strlen(short_string) + 1);
wolfPKCS11_Store_Close(store);
/* Reopen for reading */
readonly = 1;
ret = wolfPKCS11_Store_Open(type, id_tok, id_obj, readonly, &store);
fail_if(ret != 0, "Failed to reopen the vault in read-only mode: %d", ret);
/* Read out the content */
memset(secret_rd, 0, KEYVAULT_OBJ_SIZE);
ret = wolfPKCS11_Store_Read(store, secret_rd, KEYVAULT_OBJ_SIZE);
fail_if(ret != strlen(short_string) + 1);
fail_if(strcmp(short_string, secret_rd) != 0);
wolfPKCS11_Store_Close(store);
}
END_TEST
Suite *wolfboot_suite(void)
{
/* Suite initialization */
Suite *s = suite_create("wolfBoot-pkcs11-store");
TCase* tcase_store_and_load_objs = tcase_create("store_and_load_objs");
tcase_add_test(tcase_store_and_load_objs, test_store_and_load_objs);
suite_add_tcase(s, tcase_store_and_load_objs);
return s;
}
int main(void)
{
int fails;
Suite *s = wolfboot_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
fails = srunner_ntests_failed(sr);
srunner_free(sr);
return fails;
}