diff --git a/IDE/QNX/CAAM-DRIVER/Makefile b/IDE/QNX/CAAM-DRIVER/Makefile index 930551eeff6..c7129afd0e3 100644 --- a/IDE/QNX/CAAM-DRIVER/Makefile +++ b/IDE/QNX/CAAM-DRIVER/Makefile @@ -9,6 +9,15 @@ BUILD_PROFILE ?= debug CONFIG_NAME ?= $(PLATFORM)-$(BUILD_PROFILE) OUTPUT_DIR = build/$(CONFIG_NAME) TARGET = $(OUTPUT_DIR)/$(ARTIFACT) +AES_TEST_TARGET = $(OUTPUT_DIR)/test_aes_request_length +HOST_TEST_TARGET = $(OUTPUT_DIR)/test_aes_request_length_host +HOST_CC ?= cc + +ifeq ($(shell uname -s),Darwin) +HOST_TEST_LDFLAGS = -Wl,-dead_strip +else +HOST_TEST_LDFLAGS = -Wl,--gc-sections +endif #Compiler definitions @@ -67,6 +76,30 @@ $(TARGET):$(OBJS) #Rules section for default compilation and linking all: $(TARGET) +.PHONY: test host-test +test: $(AES_TEST_TARGET) host-test + +host-test: $(HOST_TEST_TARGET) + $(HOST_TEST_TARGET) + +$(AES_TEST_TARGET): test_aes_request_length.c \ + ../../../wolfcrypt/src/port/caam/caam_qnx.c \ + ../../../wolfssl/wolfcrypt/port/caam/caam_driver.h + @mkdir -p $(dir $@) + $(CC) -ffunction-sections -fdata-sections -o $@ $(INCLUDES) \ + $(CCFLAGS_all) $(CCFLAGS) $< $(LDFLAGS_all) $(LDFLAGS) \ + -Wl,--gc-sections $(LIBS_all) $(LIBS) + +$(HOST_TEST_TARGET): test_aes_request_length.c \ + ../../../wolfcrypt/src/port/caam/caam_qnx.c \ + ../../../wolfssl/wolfcrypt/port/caam/caam_driver.h \ + test_support/qnx_test_stubs.h + @mkdir -p $(dir $@) + $(HOST_CC) -D__QNXNTO__ -DCAAM_QNX_TEST_HOST \ + -ffunction-sections -fdata-sections -o $@ -Itest_support \ + $(INCLUDES) $(CCFLAGS_all) $(CCFLAGS) $< \ + $(HOST_TEST_LDFLAGS) -pthread + clean: rm -fr $(OUTPUT_DIR) diff --git a/IDE/QNX/CAAM-DRIVER/test_aes_request_length.c b/IDE/QNX/CAAM-DRIVER/test_aes_request_length.c new file mode 100644 index 00000000000..307e49a672f --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_aes_request_length.c @@ -0,0 +1,716 @@ +/* test_aes_request_length.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static ssize_t caamTestMsgReadv(resmgr_context_t* ctp, iov_t* iov, + int parts, size_t offset); +static ssize_t caamTestMsgWritev(resmgr_context_t* ctp, const iov_t* iov, + int parts, size_t offset); +static void caamTestDescInit(DESCSTRUCT* desc, int type, + unsigned int args[4], CAAM_BUFFER* buf, int sz); +static int caamTestAesCombined(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4], unsigned int phyMem); +static CAAM_ADDRESS caamTestGetPartition(unsigned int part, int partSz, + unsigned int flag); +static int caamTestFreePart(unsigned int part); +static int caamTestAead(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4]); +static int caamTestAesCmac(DESCSTRUCT* desc, int sz, + unsigned int args[4]); +static int caamTestBlob(DESCSTRUCT* desc); +static int caamTestECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4]); +static int caamTestECDSASign(DESCSTRUCT* desc, int sz, + unsigned int args[4]); +static int caamTestECDSAVerify(DESCSTRUCT* desc, CAAM_BUFFER* buf, int sz, + unsigned int args[4]); +static int caamTestECDSAEcdh(DESCSTRUCT* desc, int sz, + unsigned int args[4]); +static int caamTestEntropy(unsigned char* out, int outSz); +static int caamTestFindUnusedPartition(void); +static int caamTestKeyCover(DESCSTRUCT* desc, int sz, + unsigned int args[4]); +static void* caamTestMmap(void* addr, size_t len, int prot, int flags, + int fd, off_t offset); +static int caamTestMunmap(void* addr, size_t len); +static int caamTestMsync(void* addr, size_t len, int flags); + +#ifdef CAAM_QNX_TEST_HOST +static int caamTestSemTryWait(sem_t* sem); +static int caamTestSemPost(sem_t* sem); +static int caamTestSemInit(sem_t* sem, int shared, unsigned int value); +static int caamTestSemDestroy(sem_t* sem); + + #define sem_trywait caamTestSemTryWait + #define sem_post caamTestSemPost + #define sem_init caamTestSemInit + #define sem_destroy caamTestSemDestroy +#endif + +#define resmgr_msgreadv caamTestMsgReadv +#define resmgr_msgwritev caamTestMsgWritev +#define caamDescInit caamTestDescInit +#define caamAesCombined caamTestAesCombined +#define caamGetPartition caamTestGetPartition +#define caamFreePart caamTestFreePart +#define caamAead caamTestAead +#define caamAesCmac caamTestAesCmac +#define caamBlob caamTestBlob +#define caamECDSAMake caamTestECDSAMake +#define caamECDSASign caamTestECDSASign +#define caamECDSAVerify caamTestECDSAVerify +#define caamECDSA_ECDH caamTestECDSAEcdh +#define caamEntropy caamTestEntropy +#define caamFindUnusedPartition caamTestFindUnusedPartition +#define caamKeyCover caamTestKeyCover +#define mmap caamTestMmap +#define munmap caamTestMunmap +#define msync caamTestMsync +#define main caamQnxServerMain +#ifndef CAAM_QNX_SOURCE + #define CAAM_QNX_SOURCE "../../../wolfcrypt/src/port/caam/caam_qnx.c" +#endif +#include CAAM_QNX_SOURCE +#undef main +#undef msync +#undef munmap +#undef mmap +#undef caamKeyCover +#undef caamFindUnusedPartition +#undef caamEntropy +#undef caamECDSA_ECDH +#undef caamECDSAVerify +#undef caamECDSASign +#undef caamECDSAMake +#undef caamBlob +#undef caamAesCmac +#undef caamAead +#undef caamFreePart +#undef caamGetPartition +#undef caamAesCombined +#undef caamDescInit +#undef resmgr_msgwritev +#undef resmgr_msgreadv + +static int caamTestReadSz; +static int caamTestAesCalls; +static int caamTestFreeCalls; +static int caamTestGetPartitionCalls; +static int caamTestEcdsaCalls; +static unsigned int caamTestEcdsaPartition; +static CAAM_ADDRESS caamTestPartitionAddress; +static const unsigned char* caamTestReadData; +static size_t caamTestReadDataSz; +static unsigned char caamTestMappedBuffer[64]; +static size_t caamTestMappedLen; +static size_t caamTestMappedSensitiveLen; +static int caamTestMappedWasCleared; + +#ifdef CAAM_QNX_TEST_HOST +static int caamTestSemaphore; + +static int caamTestSemTryWait(sem_t* sem) +{ + (void)sem; + if (caamTestSemaphore == 0) + return -1; + + caamTestSemaphore = 0; + return 0; +} + +static int caamTestSemPost(sem_t* sem) +{ + (void)sem; + caamTestSemaphore++; + return 0; +} + +static int caamTestSemInit(sem_t* sem, int shared, unsigned int value) +{ + (void)sem; + (void)shared; + caamTestSemaphore = (int)value; + return 0; +} + +static int caamTestSemDestroy(sem_t* sem) +{ + (void)sem; + return 0; +} +#endif + +static void* caamTestMmap(void* addr, size_t len, int prot, int flags, + int fd, off_t offset) +{ + (void)addr; + (void)prot; + (void)flags; + (void)fd; + (void)offset; + + if (len > sizeof(caamTestMappedBuffer)) + return MAP_FAILED; + + caamTestMappedLen = len; + return caamTestMappedBuffer; +} + +static int caamTestMunmap(void* addr, size_t len) +{ + size_t i; + + if (addr == (void*)caamTestMappedBuffer && len == caamTestMappedLen) { + caamTestMappedWasCleared = 1; + for (i = 0; i < caamTestMappedSensitiveLen; i++) { + if (caamTestMappedBuffer[i] != 0) { + caamTestMappedWasCleared = 0; + break; + } + } + } + + return 0; +} + +static int caamTestMsync(void* addr, size_t len, int flags) +{ + (void)addr; + (void)len; + (void)flags; + + return 0; +} + +static ssize_t caamTestMsgReadv(resmgr_context_t* ctp, iov_t* iov, + int parts, size_t offset) +{ + int i; + size_t copied = 0; + + (void)ctp; + (void)offset; + + for (i = 0; i < parts && copied < caamTestReadDataSz; i++) { + size_t copySz = iov[i].iov_len; + + if (copySz > caamTestReadDataSz - copied) + copySz = caamTestReadDataSz - copied; + memcpy(iov[i].iov_base, caamTestReadData + copied, copySz); + copied += copySz; + } + + return caamTestReadSz; +} + +static ssize_t caamTestMsgWritev(resmgr_context_t* ctp, const iov_t* iov, + int parts, size_t offset) +{ + (void)ctp; + (void)iov; + (void)parts; + (void)offset; + + return -1; +} + +static void caamTestDescInit(DESCSTRUCT* desc, int type, + unsigned int args[4], CAAM_BUFFER* buf, int sz) +{ + (void)desc; + (void)type; + (void)args; + (void)buf; + (void)sz; +} + +static int caamTestAesCombined(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4], unsigned int phyMem) +{ + (void)desc; + (void)buf; + (void)args; + (void)phyMem; + + caamTestAesCalls++; + return Failure; +} + +static CAAM_ADDRESS caamTestGetPartition(unsigned int part, int partSz, + unsigned int flag) +{ + (void)part; + (void)partSz; + (void)flag; + caamTestGetPartitionCalls++; + return caamTestPartitionAddress; +} + +static int caamTestFreePart(unsigned int part) +{ + (void)part; + caamTestFreeCalls++; + return Success; +} + +static int caamTestAead(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4]) +{ + (void)desc; + (void)buf; + (void)args; + return Failure; +} + +static int caamTestAesCmac(DESCSTRUCT* desc, int sz, unsigned int args[4]) +{ + (void)desc; + (void)sz; + (void)args; + return Failure; +} + +static int caamTestBlob(DESCSTRUCT* desc) +{ + (void)desc; + return Failure; +} + +static int caamTestECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, + unsigned int args[4]) +{ + (void)desc; + (void)buf; + caamTestEcdsaCalls++; + args[2] = caamTestEcdsaPartition; + return Success; +} + +static int caamTestECDSASign(DESCSTRUCT* desc, int sz, + unsigned int args[4]) +{ + (void)desc; + (void)sz; + (void)args; + return Failure; +} + +static int caamTestECDSAVerify(DESCSTRUCT* desc, CAAM_BUFFER* buf, int sz, + unsigned int args[4]) +{ + (void)desc; + (void)buf; + (void)sz; + (void)args; + return Failure; +} + +static int caamTestECDSAEcdh(DESCSTRUCT* desc, int sz, + unsigned int args[4]) +{ + (void)desc; + (void)sz; + (void)args; + return Failure; +} + +static int caamTestEntropy(unsigned char* out, int outSz) +{ + (void)out; + (void)outSz; + return Failure; +} + +static int caamTestFindUnusedPartition(void) +{ + return -1; +} + +static int caamTestKeyCover(DESCSTRUCT* desc, int sz, + unsigned int args[4]) +{ + (void)desc; + (void)sz; + (void)args; + return Failure; +} + +static int testRejectIncompleteRequest(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + unsigned char scratch[48]; + unsigned int args[4] = {0U, 16U, 16U, 0U}; + int ret; + int i; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + memset(scratch, 0xA5, sizeof(scratch)); + if (sem_init(&localMemSem, 0, 1) != 0) + return 1; + + localMemory = scratch; + localPhy = 0U; + caamTestReadSz = 16; + caamTestAesCalls = 0; + ret = doAES(&ctp, &msg, args, 0U, WC_CAAM_AESECB); + localMemory = NULL; + + if (sem_destroy(&localMemSem) != 0) + return 1; + if (ret != EBADMSG || caamTestAesCalls != 0) { + printf("Unexpected result: ret=%d caamCalls=%d\n", ret, + caamTestAesCalls); + return 1; + } + + for (i = 0; i < 32; i++) { + if (scratch[i] != 0) { + printf("Scratch was not cleared at offset %d\n", i); + return 1; + } + } + + return 0; +} + +static int testClearMappedRequest(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + unsigned char request[48]; + unsigned int args[4] = {0U, 16U, 16U, 0U}; + int ret; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + memset(request, 0xA5, sizeof(request)); + memset(caamTestMappedBuffer, 0xA5, sizeof(caamTestMappedBuffer)); + if (sem_init(&localMemSem, 0, 0) != 0) + return 1; + + localMemory = NULL; + localPhy = 0U; + caamTestReadData = request; + caamTestReadDataSz = sizeof(request); + caamTestReadSz = sizeof(request); + caamTestAesCalls = 0; + caamTestMappedLen = 0U; + caamTestMappedSensitiveLen = sizeof(request); + caamTestMappedWasCleared = 0; + ret = doAES(&ctp, &msg, args, 0U, WC_CAAM_AESCBC); + caamTestReadData = NULL; + caamTestReadDataSz = 0U; + + if (sem_destroy(&localMemSem) != 0) + return 1; + if (ret != ECANCELED || caamTestAesCalls != 1 || + caamTestMappedLen != sizeof(caamTestMappedBuffer) || + !caamTestMappedWasCleared) { + return 1; + } + + return 0; +} + +static int testRejectOversizedRequest(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + unsigned int args[4] = {0U, 16U, + (unsigned int)((INT_MAX / 2) + 1), 0U}; + int ret; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + caamTestAesCalls = 0; + ret = doAES(&ctp, &msg, args, 0U, WC_CAAM_AESECB); + + return ret == EBADMSG && caamTestAesCalls == 0 ? 0 : 1; +} + +static int testRejectInvalidPartitionIndex(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + iofunc_ocb_t ocb; + unsigned int args[4]; + int ret; + int i; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + memset(&ocb, 0, sizeof(ocb)); + for (i = 0; i < MAX_OWNER_PART; i++) { + sm_ownerId[i] = 0; + sm_pagePart[i] = NO_OWNER_PART; + } + + if (!CAAM_QNX_PARTITION_IS_VALID(0U) || + !CAAM_QNX_PARTITION_IS_VALID(CAAM_QNX_MAX_PARTITIONS - 1U) || + CAAM_QNX_PARTITION_IS_VALID(CAAM_QNX_MAX_PARTITIONS) || + CAAM_QNX_PARTITION_IS_VALID(~0U)) { + return 1; + } + + memset(args, 0, sizeof(args)); + args[0] = CAAM_QNX_MAX_PARTITIONS; + args[1] = 1U; + caamTestGetPartitionCalls = 0; + ret = doGET_PART(&ctp, &msg, args, 0U, &ocb); + if (ret != EBADMSG || caamTestGetPartitionCalls != 0) + return 1; + + memset(args, 0, sizeof(args)); + args[0] = CAAM_BLACK_KEY_SM; + args[3] = 16U; + caamTestEcdsaPartition = CAAM_QNX_MAX_PARTITIONS; + caamTestEcdsaCalls = 0; + ret = doECDSA_KEYPAIR(&ctp, &msg, args, 0U, &ocb); + if (ret != EBADMSG || caamTestEcdsaCalls != 1) + return 1; + + for (i = 0; i < MAX_OWNER_PART; i++) { + if (sm_ownerId[i] != 0) + return 1; + } + + memset(args, 0, sizeof(args)); + args[0] = CAAM_QNX_MAX_PARTITIONS; + ctp.size = sizeof(msg.i) + sizeof(args); + msg.i.dcmd = WC_CAAM_FREE_PART; + caamTestFreeCalls = 0; + caamTestReadData = (const unsigned char*)args; + caamTestReadDataSz = sizeof(args); + caamTestReadSz = sizeof(args); + ret = io_devctl(&ctp, &msg, &ocb); + caamTestReadData = NULL; + caamTestReadDataSz = 0U; + + if (ret != EBADMSG || caamTestFreeCalls != 0) + return 1; + + return 0; +} + +static int testRejectOtherOwnerPartitionAccess(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + iofunc_ocb_t owner; + iofunc_ocb_t other; + unsigned int args[4]; + int commands[3] = {WC_CAAM_WRITE_PART, WC_CAAM_READ_PART, + WC_CAAM_FREE_PART}; + int ret; + int i; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + memset(&owner, 0, sizeof(owner)); + memset(&other, 0, sizeof(other)); + ctp.size = sizeof(msg.i) + sizeof(args); + msg.o.nbytes = 1U; + + for (i = 0; i < MAX_OWNER_PART; i++) { + sm_ownerId[i] = 0; + sm_pagePart[i] = NO_OWNER_PART; + } + + for (i = 0; i < 3; i++) { + memset(args, 0, sizeof(args)); + if (commands[i] == WC_CAAM_FREE_PART) { + args[0] = 0U; + } + else { + args[0] = CAAM_PAGE; + args[1] = 1U; + } + + msg.i.dcmd = commands[i]; + sm_ownerId[0] = (CAAM_ADDRESS)&owner; + sm_pagePart[0] = 0U; + caamTestFreeCalls = 0; + caamTestReadData = (const unsigned char*)args; + caamTestReadDataSz = sizeof(args); + caamTestReadSz = sizeof(args); + ret = io_devctl(&ctp, &msg, &other); + caamTestReadData = NULL; + caamTestReadDataSz = 0U; + + if (ret != EACCES || sm_ownerId[0] != (CAAM_ADDRESS)&owner || + caamTestFreeCalls != 0) { + return 1; + } + } + + return 0; +} + +static int testPartitionOwnerMapping(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + iofunc_ocb_t owner; + iofunc_ocb_t other; + CAAM_ADDRESS partAddr; + unsigned int args[4]; + int ret; + int i; + + memset(&ctp, 0, sizeof(ctp)); + memset(&msg, 0, sizeof(msg)); + memset(&owner, 0, sizeof(owner)); + memset(&other, 0, sizeof(other)); + for (i = 0; i < MAX_OWNER_PART; i++) { + sm_ownerId[i] = 0; + sm_pagePart[i] = NO_OWNER_PART; + } + + partAddr = CAAM_PAGE + (5U * CAAM_PAGE_SZ); + memset(args, 0, sizeof(args)); + args[0] = 3U; + args[1] = 1U; + caamTestPartitionAddress = partAddr; + caamTestGetPartitionCalls = 0; + ret = doGET_PART(&ctp, &msg, args, 0U, &owner); + if (ret != EOK || caamTestGetPartitionCalls != 1 || + sm_ownerId[args[0]] != (CAAM_ADDRESS)&owner) { + return 1; + } + + if (checkPartitionOwner(partAddr + 1U, &owner) != EOK || + checkPartitionOwner(partAddr + 1U, &other) != EACCES) { + return 1; + } + + ret = doGET_PART(&ctp, &msg, args, 0U, &other); + if (ret != EACCES || caamTestGetPartitionCalls != 1 || + sm_ownerId[args[0]] != (CAAM_ADDRESS)&owner) { + return 1; + } + + ctp.size = sizeof(msg.i) + sizeof(args); + msg.i.dcmd = WC_CAAM_FREE_PART; + caamTestFreeCalls = 0; + caamTestReadData = (const unsigned char*)args; + caamTestReadDataSz = sizeof(args); + caamTestReadSz = sizeof(args); + ret = io_devctl(&ctp, &msg, &owner); + caamTestReadData = NULL; + caamTestReadDataSz = 0U; + if (ret != EOK || caamTestFreeCalls != 1 || sm_ownerId[args[0]] != 0 || + sm_pagePart[5] != NO_OWNER_PART) { + return 1; + } + + return 0; +} + +static int testRejectInvalidPartitionRange(void) +{ + CAAM_ADDRESS lastPart; + + lastPart = CAAM_PAGE + + ((CAAM_QNX_MAX_PARTITIONS - 1U) * CAAM_PAGE_SZ); + + if (sanityCheckPartitionAddress(CAAM_PAGE + CAAM_PAGE_SZ - 1U, 2) == 0) + return 1; + if (sanityCheckPartitionAddress(CAAM_PAGE, 0) == 0) + return 1; + if (sanityCheckPartitionAddress(lastPart + CAAM_PAGE_SZ, 1) == 0) + return 1; + if (sanityCheckPartitionAddress(lastPart, CAAM_PAGE_SZ) != 0) + return 1; + if (sanityCheckPartitionAddress(CAAM_PAGE + 32U, 64) != 0) + return 1; + + return 0; +} + +#ifdef CAAM_QNX_TEST_HOST + #undef sem_destroy + #undef sem_init + #undef sem_post + #undef sem_trywait +#endif + +int main(void) +{ + int i; + + if (pthread_mutex_init(&sm_mutex, NULL) != EOK) + return 1; + for (i = 0; i < MAX_OWNER_PART; i++) { + sm_ownerId[i] = 0; + sm_pagePart[i] = NO_OWNER_PART; + } + if (testRejectIncompleteRequest() != 0) { + printf("testRejectIncompleteRequest: FAIL\n"); + return 1; + } + if (testClearMappedRequest() != 0) { + printf("testClearMappedRequest: FAIL\n"); + return 1; + } + if (testRejectOversizedRequest() != 0) { + printf("testRejectOversizedRequest: FAIL\n"); + return 1; + } + if (testRejectInvalidPartitionIndex() != 0) { + printf("testRejectInvalidPartitionIndex: FAIL\n"); + return 1; + } + if (testRejectOtherOwnerPartitionAccess() != 0) { + printf("testRejectOtherOwnerPartitionAccess: FAIL\n"); + return 1; + } + if (testPartitionOwnerMapping() != 0) { + printf("testPartitionOwnerMapping: FAIL\n"); + return 1; + } + if (testRejectInvalidPartitionRange() != 0) { + printf("testRejectInvalidPartitionRange: FAIL\n"); + return 1; + } + + (void)pthread_mutex_destroy(&sm_mutex); + + printf("testRejectIncompleteRequest: PASS\n"); + printf("testClearMappedRequest: PASS\n"); + printf("testRejectOversizedRequest: PASS\n"); + printf("testRejectInvalidPartitionIndex: PASS\n"); + printf("testRejectOtherOwnerPartitionAccess: PASS\n"); + printf("testPartitionOwnerMapping: PASS\n"); + printf("testRejectInvalidPartitionRange: PASS\n"); + return 0; +} diff --git a/IDE/QNX/CAAM-DRIVER/test_support/aarch64/inout.h b/IDE/QNX/CAAM-DRIVER/test_support/aarch64/inout.h new file mode 100644 index 00000000000..cac63c1db39 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/aarch64/inout.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_AARCH64_INOUT_H +#define CAAM_QNX_TEST_AARCH64_INOUT_H + +#include + +#endif /* CAAM_QNX_TEST_AARCH64_INOUT_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/devctl.h b/IDE/QNX/CAAM-DRIVER/test_support/devctl.h new file mode 100644 index 00000000000..eab2ef10999 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/devctl.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_DEVCTL_H +#define CAAM_QNX_TEST_DEVCTL_H + +#include + +#endif /* CAAM_QNX_TEST_DEVCTL_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/hw/inout.h b/IDE/QNX/CAAM-DRIVER/test_support/hw/inout.h new file mode 100644 index 00000000000..a8080187e47 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/hw/inout.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_HW_INOUT_H +#define CAAM_QNX_TEST_HW_INOUT_H + +#include + +#endif /* CAAM_QNX_TEST_HW_INOUT_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/qnx_test_stubs.h b/IDE/QNX/CAAM-DRIVER/test_support/qnx_test_stubs.h new file mode 100644 index 00000000000..a093a2c60ab --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/qnx_test_stubs.h @@ -0,0 +1,301 @@ +/* qnx_test_stubs.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + */ + +#ifndef CAAM_QNX_TEST_STUBS_H +#define CAAM_QNX_TEST_STUBS_H + +#include +#include +#include +#include + +#ifndef EOK + #define EOK 0 +#endif + +#ifndef min + #define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef NOFD + #define NOFD (-1) +#endif + +#ifndef PROT_NOCACHE + #define PROT_NOCACHE 0 +#endif + +#ifndef MAP_PHYS + #define MAP_PHYS 0 +#endif + +#ifndef MAP_ANON + #define MAP_ANON 0 +#endif + +typedef int64_t off64_t; + +typedef struct iov { + void* iov_base; + size_t iov_len; +} iov_t; + +#define SETIOV(iov, base, len) do { \ + (iov)->iov_base = (void*)(base); \ + (iov)->iov_len = (size_t)(len); \ +} while (0) + +typedef struct { + int size; + int rcvid; +} resmgr_context_t; + +typedef struct { + struct { + unsigned int dcmd; + } i; + struct { + unsigned int nbytes; + } o; +} io_devctl_t; + +typedef struct { + struct { + unsigned int xtype; + unsigned int nbytes; + } i; +} io_read_t; + +typedef struct { + int unused; +} io_write_t; + +typedef struct { + int unused; +} io_open_t; + +typedef struct { + int offset; +} iofunc_ocb_t; + +typedef iofunc_ocb_t RESMGR_OCB_T; +typedef int RESMGR_HANDLE_T; + +typedef struct { + int unused; +} iofunc_attr_t; + +typedef struct { + int (*open)(resmgr_context_t*, io_open_t*, RESMGR_HANDLE_T*, void*); +} resmgr_connect_funcs_t; + +typedef struct { + int (*close_ocb)(resmgr_context_t*, void*, RESMGR_OCB_T*); + int (*read)(resmgr_context_t*, io_read_t*, RESMGR_OCB_T*); + int (*write)(resmgr_context_t*, io_write_t*, RESMGR_OCB_T*); + int (*devctl)(resmgr_context_t*, io_devctl_t*, iofunc_ocb_t*); +} resmgr_io_funcs_t; + +typedef struct { + int unused; +} resmgr_attr_t; + +typedef struct { + int unused; +} dispatch_t; + +typedef resmgr_context_t dispatch_context_t; + +#define _RESMGR_DEFAULT 1 +#define _RESMGR_NOREPLY 2 +#define _RESMGR_CONNECT_NFUNCS 1 +#define _RESMGR_IO_NFUNCS 1 +#define _FTYPE_ANY 0 +#define _IO_XTYPE_MASK 0 +#define _IO_XTYPE_NONE 0 +#define _IO_DEVCTL_VERIFY_OCB_READ 0 +#define _IO_DEVCTL_VERIFY_OCB_WRITE 0 + +#define _DCMD_ALL 0 +#define __DIOTF(group, cmd, type) (cmd) +#define __DIOT(group, cmd, type) (cmd) + +static inline int iofunc_devctl_default(resmgr_context_t* ctp, + io_devctl_t* msg, iofunc_ocb_t* ocb) +{ + (void)ctp; + (void)msg; + (void)ocb; + return _RESMGR_DEFAULT; +} + +static inline int iofunc_devctl_verify(resmgr_context_t* ctp, + io_devctl_t* msg, iofunc_ocb_t* ocb, int flags) +{ + (void)ctp; + (void)msg; + (void)ocb; + (void)flags; + return EOK; +} + +static inline int iofunc_open_default(resmgr_context_t* ctp, io_open_t* msg, + RESMGR_HANDLE_T* handle, void* extra) +{ + (void)ctp; + (void)msg; + (void)handle; + (void)extra; + return EOK; +} + +static inline int iofunc_close_ocb_default(resmgr_context_t* ctp, + void* reserved, RESMGR_OCB_T* ocb) +{ + (void)ctp; + (void)reserved; + (void)ocb; + return EOK; +} + +static inline int iofunc_read_verify(resmgr_context_t* ctp, io_read_t* msg, + RESMGR_OCB_T* ocb, void* extra) +{ + (void)ctp; + (void)msg; + (void)ocb; + (void)extra; + return EOK; +} + +static inline void iofunc_attr_init(iofunc_attr_t* attr, int mode, + void* a, void* b) +{ + (void)attr; + (void)mode; + (void)a; + (void)b; +} + +static inline void iofunc_func_init(int a, resmgr_connect_funcs_t* b, + int c, resmgr_io_funcs_t* d) +{ + (void)a; + (void)b; + (void)c; + (void)d; +} + +static inline dispatch_t* dispatch_create(void) +{ + return (dispatch_t*)1; +} + +static inline int resmgr_attach(dispatch_t* dpp, resmgr_attr_t* attr, + const char* path, int ftype, int flags, resmgr_connect_funcs_t* cf, + resmgr_io_funcs_t* io, iofunc_attr_t* attr2) +{ + (void)dpp; + (void)attr; + (void)path; + (void)ftype; + (void)flags; + (void)cf; + (void)io; + (void)attr2; + return 0; +} + +static inline dispatch_context_t* dispatch_context_alloc(dispatch_t* dpp) +{ + (void)dpp; + return NULL; +} + +static inline dispatch_context_t* dispatch_block(dispatch_context_t* ctp) +{ + (void)ctp; + return NULL; +} + +static inline int dispatch_handler(dispatch_context_t* ctp) +{ + (void)ctp; + return 0; +} + +static inline int MsgReply(int rcvid, int status, const void* msg, int size) +{ + (void)rcvid; + (void)status; + (void)msg; + (void)size; + return 0; +} + +static inline uintptr_t mmap_device_io(size_t len, uintptr_t addr) +{ + (void)len; + return addr; +} + +static inline int munmap_device_io(uintptr_t addr, size_t len) +{ + (void)addr; + (void)len; + return 0; +} + +static inline void* mmap_device_memory(void* addr, size_t len, int prot, + int flags, uintptr_t offset) +{ + (void)addr; + (void)len; + (void)prot; + (void)flags; + (void)offset; + return NULL; +} + +static inline int mem_offset64(void* addr, int fd, int len, off64_t* offset, + void* contig_len) +{ + (void)addr; + (void)fd; + (void)len; + (void)offset; + (void)contig_len; + return -1; +} + +static inline unsigned int in32(uintptr_t addr) +{ + (void)addr; + return 0; +} + +static inline void out32(uintptr_t addr, unsigned int val) +{ + (void)addr; + (void)val; +} + +#endif /* CAAM_QNX_TEST_STUBS_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/sys/dispatch.h b/IDE/QNX/CAAM-DRIVER/test_support/sys/dispatch.h new file mode 100644 index 00000000000..505ae0a1a39 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/sys/dispatch.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_SYS_DISPATCH_H +#define CAAM_QNX_TEST_SYS_DISPATCH_H + +#include + +#endif /* CAAM_QNX_TEST_SYS_DISPATCH_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/sys/iofunc.h b/IDE/QNX/CAAM-DRIVER/test_support/sys/iofunc.h new file mode 100644 index 00000000000..86f861c7077 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/sys/iofunc.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_SYS_IOFUNC_H +#define CAAM_QNX_TEST_SYS_IOFUNC_H + +#include + +#endif /* CAAM_QNX_TEST_SYS_IOFUNC_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/sys/mman.h b/IDE/QNX/CAAM-DRIVER/test_support/sys/mman.h new file mode 100644 index 00000000000..6337e127b2b --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/sys/mman.h @@ -0,0 +1,7 @@ +#ifndef CAAM_QNX_TEST_SYS_MMAN_H +#define CAAM_QNX_TEST_SYS_MMAN_H + +#include_next +#include + +#endif /* CAAM_QNX_TEST_SYS_MMAN_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/sys/neutrino.h b/IDE/QNX/CAAM-DRIVER/test_support/sys/neutrino.h new file mode 100644 index 00000000000..9c4cd2148f1 --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/sys/neutrino.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_SYS_NEUTRINO_H +#define CAAM_QNX_TEST_SYS_NEUTRINO_H + +#include + +#endif /* CAAM_QNX_TEST_SYS_NEUTRINO_H */ diff --git a/IDE/QNX/CAAM-DRIVER/test_support/sys/resmgr.h b/IDE/QNX/CAAM-DRIVER/test_support/sys/resmgr.h new file mode 100644 index 00000000000..5dcf63e355b --- /dev/null +++ b/IDE/QNX/CAAM-DRIVER/test_support/sys/resmgr.h @@ -0,0 +1,6 @@ +#ifndef CAAM_QNX_TEST_SYS_RESMGR_H +#define CAAM_QNX_TEST_SYS_RESMGR_H + +#include + +#endif /* CAAM_QNX_TEST_SYS_RESMGR_H */ diff --git a/tests/caam_qnx_blob.test b/tests/caam_qnx_blob.test new file mode 100755 index 00000000000..f06cafb1a42 --- /dev/null +++ b/tests/caam_qnx_blob.test @@ -0,0 +1,196 @@ +#!/bin/sh +# +# Portable white-box regression for the QNX CAAM BLOB handler. The generated +# harness uses the source function with safe stubs, so it can verify that an +# oversized key modifier is rejected before request data is read without a +# QNX SDK or device. + +set -eu + +script_dir=$(unset CDPATH; cd "$(dirname "$0")" && pwd) +source_file="" + +for source_root in "${top_srcdir:-}" "${srcdir:-}/.." "$script_dir/.."; do + if test -n "$source_root" && \ + test -r "$source_root/wolfcrypt/src/port/caam/caam_qnx.c"; then + source_file="$source_root/wolfcrypt/src/port/caam/caam_qnx.c" + break + fi +done + +if test -z "$source_file"; then + echo "caam_qnx_blob_keymod_bound: source file not found" >&2 + exit 1 +fi + +compiler=${CC_FOR_BUILD:-cc} +compiler_bin=${compiler%% *} +if ! command -v "$compiler_bin" >/dev/null 2>&1; then + echo "caam_qnx_blob_keymod_bound: compiler not available, skipping" >&2 + exit 77 +fi + +tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/wolfssl-caam-qnx.XXXXXX") +trap 'rm -rf "$tmp_dir"' 0 1 2 3 15 +harness="$tmp_dir/caam_qnx_blob.c" +binary="$tmp_dir/caam_qnx_blob" + +cat > "$harness" <<'EOF' +#include +#include +#include + +#ifndef EOVERFLOW + #define EOVERFLOW 75 +#endif +#ifndef EBADMSG + #define EBADMSG 74 +#endif +#ifndef ECANCELED + #define ECANCELED 125 +#endif + +#define EOK 0 +#define BLACK_KEY_MAC_SZ 16 +#define BLACK_BLOB_KEYMOD_SZ 16 +#define CAAM_BLOB_ENCAP 1 +#define CAAM_BLOB_DECAP 2 +#define WC_CAAM_BLOB_ENCAP 3 +#define Success 1 + +typedef unsigned long CAAM_ADDRESS; + +typedef struct DESCSTRUCT { + int unused; +} DESCSTRUCT; + +typedef struct CAAM_BUFFER { + CAAM_ADDRESS TheAddress; + int Length; +} CAAM_BUFFER; + +typedef struct iov { + void* iov_base; + unsigned int iov_len; +} iov_t; + +typedef struct resmgr_context { + unsigned int size; +} resmgr_context_t; + +typedef struct io_devctl { + struct { + int dcmd; + } i; + struct { + unsigned int nbytes; + } o; +} io_devctl_t; + +#define SETIOV(iov, addr, sz) \ + do { \ + (iov)->iov_base = (void*)(addr); \ + (iov)->iov_len = (unsigned int)(sz); \ + } while (0) + +static unsigned char mapped[1]; +static int read_calls; + +static void* CAAM_ADR_MAP(CAAM_ADDRESS in, int inSz, unsigned char copy) +{ + (void)in; + (void)inSz; + (void)copy; + return mapped; +} + +static void CAAM_ADR_UNMAP(void* vaddr, CAAM_ADDRESS out, int outSz, + unsigned char copy) +{ + (void)vaddr; + (void)out; + (void)outSz; + (void)copy; +} + +static int CAAM_ADR_SYNC(void* vaddr, int sz) +{ + (void)vaddr; + (void)sz; + return 0; +} + +static int resmgr_msgreadv(resmgr_context_t* ctp, iov_t* iov, int iovcnt, + unsigned int idx) +{ + (void)ctp; + (void)iov; + (void)iovcnt; + (void)idx; + read_calls++; + return 0; +} + +static int resmgr_msgwritev(resmgr_context_t* ctp, iov_t* iov, int iovcnt, + unsigned int idx) +{ + (void)ctp; + (void)iov; + (void)iovcnt; + (void)idx; + return 0; +} + +static void caamDescInit(DESCSTRUCT* desc, int dir, unsigned int args[4], + CAAM_BUFFER tmp[3], int count) +{ + (void)desc; + (void)dir; + (void)args; + (void)tmp; + (void)count; +} + +static int caamBlob(DESCSTRUCT* desc) +{ + (void)desc; + return 0; +} +EOF + +sed -n '/^static int doBLOB(/,/^}/p' "$source_file" >> "$harness" + +cat >> "$harness" <<'EOF' +int main(void) +{ + resmgr_context_t ctp; + io_devctl_t msg; + unsigned int args[4] = { 0, 0, 1, BLACK_BLOB_KEYMOD_SZ }; + int ret; + + ctp.size = 64; + msg.i.dcmd = WC_CAAM_BLOB_ENCAP; + msg.o.nbytes = 64; + + read_calls = 0; + ret = doBLOB(&ctp, &msg, args, 0); + if (ret != EBADMSG || read_calls != 1) { + printf("caam_qnx_blob_keymod_bound: valid boundary failed\n"); + return 1; + } + + args[3] = BLACK_BLOB_KEYMOD_SZ + 1; + read_calls = 0; + ret = doBLOB(&ctp, &msg, args, 0); + if (ret != EOVERFLOW || read_calls != 0) { + printf("caam_qnx_blob_keymod_bound: oversized value was not rejected\n"); + return 1; + } + + printf("caam_qnx_blob_keymod_bound: PASS\n"); + return 0; +} +EOF + +$compiler -Wall -Wextra -o "$binary" "$harness" +"$binary" diff --git a/tests/include.am b/tests/include.am index c19499a3f64..9462ca38483 100644 --- a/tests/include.am +++ b/tests/include.am @@ -5,6 +5,7 @@ if BUILD_TESTS noinst_PROGRAMS += tests/unit.test +dist_noinst_SCRIPTS += tests/caam_qnx_blob.test tests_unit_test_SOURCES = \ tests/unit.c \ tests/api.c \ diff --git a/wolfcrypt/src/port/caam/caam_driver.c b/wolfcrypt/src/port/caam/caam_driver.c index dd5e2749718..80fff6e21a1 100644 --- a/wolfcrypt/src/port/caam/caam_driver.c +++ b/wolfcrypt/src/port/caam/caam_driver.c @@ -78,6 +78,17 @@ struct CAAM_DEVICE { static struct CAAM_DEVICE caam; +#if defined(__QNX__) || defined(__QNXNTO__) +static unsigned int caamGetPartitionCount(void) +{ + unsigned int lastPartition; + + lastPartition = (CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMVID_MS) >> 12U) & + 0xFU; + return lastPartition + 1U; +} +#endif + /* function declarations */ Error caamAddJob(DESCSTRUCT* desc); Error caamDoJob(DESCSTRUCT* desc); @@ -169,7 +180,7 @@ static void printSecureMemoryInfo() printf("SMPO = 0x%08X\n", CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO)); SMVID_MS = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMVID_MS); SMVID_LS = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMVID_LS); - printf("\tNumber Partitions : %d\n", ((SMVID_MS >> 12) & 0xFU)); + printf("\tHighest Partition : %d\n", ((SMVID_MS >> 12) & 0xFU)); printf("\tNumber Pages : %d\n", (SMVID_MS & 0x3FFU)); printf("\tPage Size : 2^%d\n", ((SMVID_LS >> 16) & 0x7U)); } @@ -244,6 +255,14 @@ Error caamFreePart(unsigned int part) { unsigned int status; +#if defined(__QNX__) || defined(__QNXNTO__) + if (!CAAM_QNX_PARTITION_IS_VALID(part) || + part >= caamGetPartitionCount()) { + WOLFSSL_MSG("invalid secure memory partition"); + return CAAM_ARGS_E; + } +#endif + #if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT) printf("freeing partition %d\n", part); #endif @@ -270,10 +289,15 @@ static Error caamFreeAllPart() { unsigned int SMPO; unsigned int i; +#if defined(__QNX__) || defined(__QNXNTO__) + unsigned int partitionCount = caamGetPartitionCount(); +#else + unsigned int partitionCount = 15U; +#endif WOLFSSL_MSG("Free all partitions"); SMPO = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO); - for (i = 0; i < 15U; i = i + 1U) { + for (i = 0; i < partitionCount; i = i + 1U) { if ((SMPO & (0x3U << (i * 2U))) == (0x3U << (i * 2U))) { caamFreePart(i); } @@ -291,9 +315,14 @@ int caamFindUnusedPartition() unsigned int SMPO; unsigned int i; int ret = -1; +#if defined(__QNX__) || defined(__QNXNTO__) + unsigned int partitionCount = caamGetPartitionCount(); +#else + unsigned int partitionCount = 15U; +#endif SMPO = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO); - for (i = 0; i < 15U; i = i + 1) { + for (i = 0; i < partitionCount; i = i + 1U) { if ((SMPO & (0x3U << (i * 2U))) == 0U) { ret = (int)i; break; @@ -313,6 +342,12 @@ static Error caamCreatePartition(unsigned int* page, unsigned int par, int testPage; unsigned int status; +#if defined(__QNX__) || defined(__QNXNTO__) + if (!CAAM_QNX_PARTITION_IS_VALID(par) || + par >= caamGetPartitionCount()) + return CAAM_ARGS_E; +#endif + /* check ownership of partition */ status = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO); if ((status & (0x3U << (par * 2))) > 0) { @@ -372,6 +407,14 @@ CAAM_ADDRESS caamGetPartition(unsigned int part, int partSz, unsigned int flag) (void)flag; /* flag is for future changes to flag passed when creating */ +#if defined(__QNX__) || defined(__QNXNTO__) + if (!CAAM_QNX_PARTITION_IS_VALID(part) || + part >= caamGetPartitionCount()) { + WOLFSSL_MSG("invalid secure memory partition"); + return 0; + } +#endif + /* create and claim the partition */ err = caamCreatePartition(&part, part, CAAM_SM_CSP | CAAM_SM_SMAP_LOCK | CAAM_SM_CSP | CAAM_SM_ALL_RW); @@ -1248,6 +1291,7 @@ int caamECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4]) { Error err; unsigned int part = 0; + unsigned int page = 0; unsigned int isBlackKey = 0; unsigned int pdECDSEL = 0; unsigned int phys; @@ -1271,8 +1315,9 @@ int caamECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4]) return -1; } - /* create and claim the partition */ - err = caamCreatePartition(&part, part, CAAM_SM_CSP | CAAM_SM_SMAP_LOCK | + /* create and claim the partition, the allocated page is returned in + * page while part keeps the partition number */ + err = caamCreatePartition(&page, part, CAAM_SM_CSP | CAAM_SM_SMAP_LOCK | CAAM_SM_CSP | CAAM_SM_ALL_RW); if (err != Success) { WOLFSSL_MSG("error creating partition for secure ecc key"); @@ -1280,7 +1325,7 @@ int caamECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4]) } /* map secure partition to virtual address */ - phys = (CAAM_PAGE + (part << 12)); + phys = (CAAM_PAGE + (page << 12)); pt = (unsigned char*)buf[0].TheAddress; pt[0] = (phys >> 24) & 0xFF; pt[1] = (phys >> 16) & 0xFF; diff --git a/wolfcrypt/src/port/caam/caam_qnx.c b/wolfcrypt/src/port/caam/caam_qnx.c index 1436df24df7..1590933f6a2 100644 --- a/wolfcrypt/src/port/caam/caam_qnx.c +++ b/wolfcrypt/src/port/caam/caam_qnx.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -55,6 +56,16 @@ static void* localMemory = NULL; static unsigned int localPhy = 0; sem_t localMemSem; +static void caamZeroMemory(void* mem, size_t len) +{ + volatile unsigned char* p = (volatile unsigned char*)mem; + + while (len > 0U) { + *p++ = 0; + len--; + } +} + /* Can be overridden, variable for how large of a local buffer to have. * This allows for large performance gains when avoiding mapping new memory * for each operation. */ @@ -80,9 +91,11 @@ sem_t localMemSem; #endif /* keep track of which ID memory belongs to so it can be free'd up */ -#define MAX_PART 7 +#define MAX_OWNER_PART CAAM_QNX_MAX_PARTITIONS +#define NO_OWNER_PART MAX_OWNER_PART pthread_mutex_t sm_mutex; -CAAM_ADDRESS sm_ownerId[MAX_PART]; +CAAM_ADDRESS sm_ownerId[MAX_OWNER_PART]; +unsigned int sm_pagePart[MAX_OWNER_PART]; /* variables for I/O of resource manager */ resmgr_connect_funcs_t connect_funcs; @@ -332,8 +345,17 @@ int CAAM_ADR_SYNC(void* vaddr, int sz) */ static int sanityCheckPartitionAddress(CAAM_ADDRESS partAddr, int partSz) { - if (partAddr < CAAM_PAGE || partAddr > CAAM_PAGE + (MAX_PART*4096) || - partSz > 4096) { + CAAM_ADDRESS partOffset; + + if (partAddr < CAAM_PAGE || partSz <= 0) { + WOLFSSL_MSG("error in physical address range"); + return -1; + } + + partOffset = partAddr - CAAM_PAGE; + if ((partOffset / CAAM_PAGE_SZ) >= CAAM_QNX_MAX_PARTITIONS || + (CAAM_ADDRESS)partSz > (CAAM_ADDRESS)CAAM_PAGE_SZ - + (partOffset % CAAM_PAGE_SZ)) { WOLFSSL_MSG("error in physical address range"); return -1; } @@ -341,6 +363,44 @@ static int sanityCheckPartitionAddress(CAAM_ADDRESS partAddr, int partSz) } +static int checkPartitionOwner(CAAM_ADDRESS partAddr, iofunc_ocb_t *ocb) +{ + unsigned int pageNumber; + unsigned int partNumber; + int ret = EOK; + + pageNumber = (unsigned int)((partAddr - CAAM_PAGE) / CAAM_PAGE_SZ); + if (!CAAM_QNX_PARTITION_IS_VALID(pageNumber)) + return EBADMSG; + + if (pthread_mutex_lock(&sm_mutex) != EOK) { + return ECANCELED; + } + else { + partNumber = sm_pagePart[pageNumber]; + if (!CAAM_QNX_PARTITION_IS_VALID(partNumber) || + sm_ownerId[partNumber] != (CAAM_ADDRESS)ocb) { + ret = EACCES; + } + pthread_mutex_unlock(&sm_mutex); + } + + return ret; +} + + +static void clearPartitionOwner(unsigned int partNumber) +{ + unsigned int i; + + sm_ownerId[partNumber] = 0; + for (i = 0; i < MAX_OWNER_PART; i++) { + if (sm_pagePart[i] == partNumber) + sm_pagePart[i] = NO_OWNER_PART; + } +} + + /* return 0 on success */ static int getArgs(unsigned int args[4], resmgr_context_t *ctp, io_devctl_t *msg, unsigned int *idx, unsigned int maxIdx) @@ -553,6 +613,10 @@ static int doBLOB(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], inSz = inSz + BLACK_KEY_MAC_SZ; } + if (args[3] > sizeof(keymod)) { + return EOVERFLOW; + } + SETIOV(&in_iovs[0], keymod, args[3]); if ((inSz + args[3]) > (ctp->size - idx)) { return EOVERFLOW; @@ -809,7 +873,7 @@ static int doAES(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], int readSz; unsigned char *key = NULL, *iv = NULL, *in = NULL, *out = NULL; unsigned char *pt = NULL; - int keySz, ivSz = 0, inSz, outSz; + int keySz, ivSz = 0, inSz, outSz, expectedReadSz; unsigned int totalSz; unsigned int phyMem = 0; int useLocalMem = 0; @@ -839,11 +903,18 @@ static int doAES(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], ivSz = 16; } - totalSz = (unsigned int)keySz + (unsigned int)inSz + - (unsigned int)outSz + (unsigned int)ivSz; + if (inSz < 0 || keySz > INT_MAX - inSz || + keySz + inSz > INT_MAX - ivSz) { + return EBADMSG; + } + expectedReadSz = keySz + inSz + ivSz; + if (expectedReadSz > INT_MAX - outSz) { + return EBADMSG; + } + totalSz = (unsigned int)expectedReadSz + (unsigned int)outSz; if (totalSz < WOLFSSL_CAAM_QNX_MEMORY) { - if (sem_trywait(&localMemSem) == 0) { + if (localMemory != NULL && sem_trywait(&localMemSem) == 0) { key = localMemory; phyMem = localPhy; useLocalMem = 1; @@ -897,15 +968,15 @@ static int doAES(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], } if (ret == EOK) { + if (pt == NULL) + caamZeroMemory(key, (size_t)expectedReadSz); + readSz = resmgr_msgreadv(ctp, in_iovs, inIdx, idx); if (readSz < 0) { ret = ECANCELED; } - else if (readSz < (keySz + ivSz + inSz)) { - /* sanity check that enough data was sent, otherwise part of the - * buffer would be left holding data from a previous operation */ - WOLFSSL_MSG("not enough input data sent for AES operation"); - ret = EOVERFLOW; + else if (readSz != expectedReadSz) { + ret = EBADMSG; } } @@ -960,11 +1031,17 @@ static int doAES(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], } if (pt != NULL) { + /* wipe the whole buffer, including the output region, so decrypted + * data does not stay resident in the mapping being released */ + caamZeroMemory(key, (size_t)totalSz); CAAM_ADR_UNMAP(pt, 0, totalSz, 0); } if (useLocalMem) { - /* done using local mapped memory */ + /* done using local mapped memory, wipe the whole buffer including the + * output region since this memory persists between operations */ + if (key != NULL) + caamZeroMemory(key, (size_t)totalSz); sem_post(&localMemSem); } @@ -981,6 +1058,9 @@ static int doECDSA_KEYPAIR(resmgr_context_t *ctp, io_devctl_t *msg, int ret = EOK; int keySz; int privSz; + unsigned int partNumber; + unsigned int pageNumber; + CAAM_ADDRESS keyAddr; DESCSTRUCT desc; CAAM_BUFFER tmp[2]; iov_t out_iovs[3]; @@ -1019,6 +1099,11 @@ static int doECDSA_KEYPAIR(resmgr_context_t *ctp, io_devctl_t *msg, } } + if (ret == EOK && args[0] == CAAM_BLACK_KEY_SM && + !CAAM_QNX_PARTITION_IS_VALID(args[2])) { + ret = EBADMSG; + } + if (ret == EOK) { SETIOV(&out_iovs[0], tmp[0].TheAddress, privSz); SETIOV(&out_iovs[1], tmp[1].TheAddress, keySz * 2); @@ -1028,13 +1113,23 @@ static int doECDSA_KEYPAIR(resmgr_context_t *ctp, io_devctl_t *msg, } } - /* claim ownership of a secure memory location */ + /* claim ownership so later sign/ECDH can check the caller. args[2] is the + * partition, priv holds the key's physical address used to find the page */ if (ret == EOK && args[0] == CAAM_BLACK_KEY_SM) { - if (pthread_mutex_lock(&sm_mutex) != EOK) { + partNumber = args[2]; + keyAddr = ((CAAM_ADDRESS)priv[0] << 24) | ((CAAM_ADDRESS)priv[1] << 16) | + ((CAAM_ADDRESS)priv[2] << 8) | (CAAM_ADDRESS)priv[3]; + pageNumber = (unsigned int)((keyAddr - CAAM_PAGE) / CAAM_PAGE_SZ); + if (!CAAM_QNX_PARTITION_IS_VALID(partNumber) || + !CAAM_QNX_PARTITION_IS_VALID(pageNumber)) { + ret = EBADMSG; + } + else if (pthread_mutex_lock(&sm_mutex) != EOK) { ret = ECANCELED; } else { - sm_ownerId[args[2]] = (CAAM_ADDRESS)ocb; + sm_ownerId[partNumber] = (CAAM_ADDRESS)ocb; + sm_pagePart[pageNumber] = partNumber; pthread_mutex_unlock(&sm_mutex); } } @@ -1157,7 +1252,7 @@ static int doECDSA_VERIFY(resmgr_context_t *ctp, io_devctl_t *msg, * returns EOK on success */ static int doECDSA_SIGN(resmgr_context_t *ctp, io_devctl_t *msg, - unsigned int args[4], unsigned int idx) + unsigned int args[4], unsigned int idx, iofunc_ocb_t *ocb) { int ret, keySz; DESCSTRUCT desc; @@ -1200,6 +1295,15 @@ static int doECDSA_SIGN(resmgr_context_t *ctp, io_devctl_t *msg, return EOVERFLOW; } + /* a secure memory key is referenced only by its address, reject one that + * the caller does not own so it can not sign with another client's key */ + if (args[0] == CAAM_BLACK_KEY_SM) { + ret = checkPartitionOwner(blackKey, ocb); + if (ret != EOK) { + CAAM_ADR_UNMAP(hash, 0, args[2], 0); + return ret; + } + } /* setup CAAM buffers to pass to driver */ if (args[0] == CAAM_BLACK_KEY_SM) { @@ -1271,7 +1375,7 @@ static int doECDSA_SIGN(resmgr_context_t *ctp, io_devctl_t *msg, * returns EOK on success */ static int doECDSA_ECDH(resmgr_context_t *ctp, io_devctl_t *msg, - unsigned int args[4], unsigned int idx) + unsigned int args[4], unsigned int idx, iofunc_ocb_t *ocb) { int ret; DESCSTRUCT desc; @@ -1333,6 +1437,18 @@ static int doECDSA_ECDH(resmgr_context_t *ctp, io_devctl_t *msg, return ECANCELED; } + /* a secure memory private key is referenced only by its address, reject + * one the caller does not own so it can not derive with another client's + * key */ + if (args[0] == CAAM_BLACK_KEY_SM) { + ret = checkPartitionOwner(blackKey, ocb); + if (ret != EOK) { + if (pubkey != NULL) + CAAM_ADR_UNMAP(pubkey, 0, args[3]*2, 0); + return ret; + } + } + /* setup CAAM buffers to pass to driver */ if (args[1] == CAAM_BLACK_KEY_SM) { tmp[0].TheAddress = securePub; @@ -1447,7 +1563,8 @@ static int doFIFO_S(resmgr_context_t *ctp, io_devctl_t *msg, static int doGET_PART(resmgr_context_t *ctp, io_devctl_t *msg, unsigned int args[4], unsigned int idx, iofunc_ocb_t *ocb) { - int partNumber; + unsigned int partNumber; + unsigned int pageNumber; int partSz; CAAM_ADDRESS partAddr; iov_t out_iov; @@ -1455,21 +1572,39 @@ static int doGET_PART(resmgr_context_t *ctp, io_devctl_t *msg, partNumber = args[0]; partSz = args[1]; - partAddr = caamGetPartition(partNumber, partSz, 0); - if (partAddr == 0) { + if (!CAAM_QNX_PARTITION_IS_VALID(partNumber)) return EBADMSG; - } - - SETIOV(&out_iov, &partAddr, sizeof(CAAM_ADDRESS)); - resmgr_msgwritev(ctp, &out_iov, 1, sizeof(msg->o)); if (pthread_mutex_lock(&sm_mutex) != EOK) { return ECANCELED; } - else { - sm_ownerId[partNumber] = (CAAM_ADDRESS)ocb; + + if (sm_ownerId[partNumber] != 0 && + sm_ownerId[partNumber] != (CAAM_ADDRESS)ocb) { pthread_mutex_unlock(&sm_mutex); + return EACCES; } + + partAddr = caamGetPartition(partNumber, partSz, 0); + if (partAddr == 0) { + pthread_mutex_unlock(&sm_mutex); + return EBADMSG; + } + + pageNumber = (unsigned int)((partAddr - CAAM_PAGE) / CAAM_PAGE_SZ); + if (!CAAM_QNX_PARTITION_IS_VALID(pageNumber) || + (sm_pagePart[pageNumber] != NO_OWNER_PART && + sm_pagePart[pageNumber] != partNumber)) { + pthread_mutex_unlock(&sm_mutex); + return ECANCELED; + } + + sm_ownerId[partNumber] = (CAAM_ADDRESS)ocb; + sm_pagePart[pageNumber] = partNumber; + pthread_mutex_unlock(&sm_mutex); + + SETIOV(&out_iov, &partAddr, sizeof(CAAM_ADDRESS)); + resmgr_msgwritev(ctp, &out_iov, 1, sizeof(msg->o)); return EOK; } @@ -1478,7 +1613,7 @@ static int doGET_PART(resmgr_context_t *ctp, io_devctl_t *msg, * returns EOK on success */ static int doWRITE_PART(resmgr_context_t *ctp, io_devctl_t *msg, - unsigned int args[4], unsigned int idx) + unsigned int args[4], unsigned int idx, iofunc_ocb_t *ocb) { int partSz, ret; CAAM_ADDRESS partAddr; @@ -1490,6 +1625,15 @@ static int doWRITE_PART(resmgr_context_t *ctp, io_devctl_t *msg, partAddr = args[0]; partSz = args[1]; + /* sanity check on address and length */ + if (sanityCheckPartitionAddress(partAddr, partSz) != 0) { + return EBADMSG; + } + + ret = checkPartitionOwner(partAddr, ocb); + if (ret != EOK) + return ret; + buf = (unsigned char*)CAAM_ADR_MAP(0, partSz, 0); if (buf == NULL) { return ECANCELED; @@ -1502,12 +1646,6 @@ static int doWRITE_PART(resmgr_context_t *ctp, io_devctl_t *msg, return EBADMSG; } - /* sanity check on address and length */ - if (sanityCheckPartitionAddress(partAddr, partSz) != 0) { - CAAM_ADR_UNMAP(buf, 0, partSz, 0); - return EBADMSG; - } - vaddr = CAAM_ADR_TO_VIRTUAL(partAddr, partSz); if (vaddr == 0) { CAAM_ADR_UNMAP(buf, 0, partSz, 0); @@ -1524,9 +1662,9 @@ static int doWRITE_PART(resmgr_context_t *ctp, io_devctl_t *msg, * returns EOK on success */ static int doREAD_PART(resmgr_context_t *ctp, io_devctl_t *msg, - unsigned int args[4], unsigned int idx) + unsigned int args[4], unsigned int idx, iofunc_ocb_t *ocb) { - int partSz; + int partSz, ret; CAAM_ADDRESS partAddr; CAAM_ADDRESS vaddr; unsigned char *buf; @@ -1546,6 +1684,10 @@ static int doREAD_PART(resmgr_context_t *ctp, io_devctl_t *msg, return EBADMSG; } + ret = checkPartitionOwner(partAddr, ocb); + if (ret != EOK) + return ret; + buf = (unsigned char*)CAAM_ADR_MAP(0, partSz, 0); if (buf == NULL) { return ECANCELED; @@ -1632,11 +1774,11 @@ int io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, iofunc_ocb_t *ocb) break; case WC_CAAM_ECDSA_SIGN: - ret = doECDSA_SIGN(ctp, msg, args, idx); + ret = doECDSA_SIGN(ctp, msg, args, idx, ocb); break; case WC_CAAM_ECDSA_ECDH: - ret = doECDSA_ECDH(ctp, msg, args, idx); + ret = doECDSA_ECDH(ctp, msg, args, idx, ocb); break; case WC_CAAM_FIFO_S: @@ -1648,13 +1790,24 @@ int io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, iofunc_ocb_t *ocb) break; case WC_CAAM_FREE_PART: - caamFreePart(args[0]); + if (!CAAM_QNX_PARTITION_IS_VALID(args[0])) { + ret = EBADMSG; + break; + } if (pthread_mutex_lock(&sm_mutex) != EOK) { ret = ECANCELED; } + else if (sm_ownerId[args[0]] != (CAAM_ADDRESS)ocb) { + pthread_mutex_unlock(&sm_mutex); + ret = EACCES; + } + else if (caamFreePart(args[0]) != Success) { + pthread_mutex_unlock(&sm_mutex); + ret = ECANCELED; + } else { - sm_ownerId[args[0]] = 0; + clearPartitionOwner(args[0]); pthread_mutex_unlock(&sm_mutex); ret = EOK; } @@ -1672,11 +1825,11 @@ int io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, iofunc_ocb_t *ocb) break; case WC_CAAM_WRITE_PART: - ret = doWRITE_PART(ctp, msg, args, idx); + ret = doWRITE_PART(ctp, msg, args, idx, ocb); break; case WC_CAAM_READ_PART: - ret = doREAD_PART(ctp, msg, args, idx); + ret = doREAD_PART(ctp, msg, args, idx, ocb); break; default: @@ -1707,9 +1860,9 @@ int io_close_ocb(resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb) return ECANCELED; } else { - for (i = 0; i < MAX_PART; i++) { + for (i = 0; i < MAX_OWNER_PART; i++) { if (sm_ownerId[i] == (CAAM_ADDRESS)ocb) { - sm_ownerId[i] = 0; + clearPartitionOwner((unsigned int)i); #if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT) printf("found dangiling partition at index %d\n", i); #endif @@ -1796,8 +1949,9 @@ int main(int argc, char *argv[]) int i; pthread_mutex_init(&sm_mutex, NULL); - for (i = 0; i < MAX_PART; i++) { + for (i = 0; i < MAX_OWNER_PART; i++) { sm_ownerId[i] = 0; + sm_pagePart[i] = NO_OWNER_PART; } if (InitCAAM() != 0) { diff --git a/wolfssl/wolfcrypt/port/caam/caam_driver.h b/wolfssl/wolfcrypt/port/caam/caam_driver.h index 87d135fb60f..3a3c5f5b4d8 100644 --- a/wolfssl/wolfcrypt/port/caam/caam_driver.h +++ b/wolfssl/wolfcrypt/port/caam/caam_driver.h @@ -60,6 +60,12 @@ #define CAAM_PAGE_MAX 6 +#if defined(__QNX__) || defined(__QNXNTO__) + #define CAAM_QNX_MAX_PARTITIONS 16U + #define CAAM_QNX_PARTITION_IS_VALID(part) \ + ((unsigned int)(part) < CAAM_QNX_MAX_PARTITIONS) +#endif + /* max size of 64 word32's */ #define CAAM_DESC_MAX 256