/* 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 KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_ECC256 #include #include #include #include #include #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 #include #include #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" 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; char secret1[] = "Everyone gets Friday off."; char secret2[] = "This is just a test string."; 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); ck_assert(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); ck_assert_msg(ret == 0, "Failed to open the vault: %d", ret); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == strlen(secret1) + strlen(secret2) + 2); ck_assert(strcmp(secret1, secret_rd) == 0); ck_assert(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); ck_assert_msg(ret == 0, "Failed to open the 2nd vault: %d", ret); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == strlen(secret2) + 1); ck_assert(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); ck_assert_msg(ret == 0, "Failed to create vault: %d", ret); ck_assert_msg(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); ck_assert_msg(ret == 0, "Failed to create vault: %d", ret); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == strlen(secret2) + 1); ck_assert(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); ck_assert_msg(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); ck_assert_msg(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); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == strlen(secret2) + 1); ck_assert(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); ck_assert_msg(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); ck_assert(ret == strlen(secret2) + 1); ck_assert(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); ck_assert_msg(ret == 0, "Failed to create vault: %d", ret); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == KEYVAULT_OBJ_SIZE - 8); ck_assert(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); ck_assert_msg(ret == 0, "Failed to create vault: %d", ret); ck_assert_msg(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); ck_assert_msg(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); ck_assert(ret == strlen(short_string) + 1); ck_assert(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; }