mirror of https://github.com/wolfSSL/wolfTPM.git
405 lines
12 KiB
C
405 lines
12 KiB
C
/* unit_tests.c
|
|
*
|
|
* Copyright (C) 2006-2022 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfTPM.
|
|
*
|
|
* wolfTPM 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfTPM 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
|
|
*/
|
|
|
|
/* wolfTPM 2.0 unit tests */
|
|
|
|
|
|
#include <wolftpm/tpm2.h>
|
|
#include <wolftpm/tpm2_wrap.h>
|
|
#include <wolftpm/tpm2_param_enc.h>
|
|
|
|
#include <hal/tpm_io.h>
|
|
#include <examples/tpm_test.h>
|
|
#include <examples/wrap/wrap_test.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
/* Test Fail Helpers */
|
|
#ifndef NO_ABORT
|
|
#ifndef XABORT
|
|
#include <stdlib.h>
|
|
#define XABORT() abort()
|
|
#endif
|
|
#else
|
|
#undef XABORT
|
|
#define XABORT()
|
|
#endif
|
|
|
|
#define Fail(description, result) do { \
|
|
printf("\nERROR - %s line %d failed with:", __FILE__, __LINE__); \
|
|
printf("\n expected: "); printf description; \
|
|
printf("\n result: "); printf result; printf("\n\n"); \
|
|
fflush(stdout); \
|
|
XABORT(); \
|
|
} while(0)
|
|
#define Assert(test, description, result) if (!(test)) Fail(description, result)
|
|
#define AssertTrue(x) Assert( (x), ("%s is true", #x), (#x " => FALSE"))
|
|
#define AssertFalse(x) Assert(!(x), ("%s is false", #x), (#x " => TRUE"))
|
|
#define AssertNotNull(x) Assert( (x), ("%s is not null", #x), (#x " => NULL"))
|
|
#define AssertNull(x) do { \
|
|
void* _x = (void *) (x); \
|
|
Assert(!_x, ("%s is null", #x), (#x " => %p", _x)); \
|
|
} while(0)
|
|
#define AssertInt(x, y, op, er) do { \
|
|
int _x = (int)x; \
|
|
int _y = (int)y; \
|
|
Assert(_x op _y, ("%s " #op " %s", #x, #y), ("%d(0x%x) " #er " %d(0x%x)", \
|
|
_x, _x, _y, _y)); \
|
|
} while(0)
|
|
#define AssertIntEQ(x, y) AssertInt(x, y, ==, !=)
|
|
#define AssertIntNE(x, y) AssertInt(x, y, !=, ==)
|
|
#define AssertIntGT(x, y) AssertInt(x, y, >, <=)
|
|
#define AssertIntLT(x, y) AssertInt(x, y, <, >=)
|
|
#define AssertIntGE(x, y) AssertInt(x, y, >=, <)
|
|
#define AssertIntLE(x, y) AssertInt(x, y, <=, >)
|
|
#define AssertStr(x, y, op, er) do { \
|
|
const char* _x = x; \
|
|
const char* _y = y; \
|
|
int _z = (_x && _y) ? strcmp(_x, _y) : -1; \
|
|
Assert(_z op 0, ("%s " #op " %s", #x, #y), \
|
|
("\"%s\" " #er " \"%s\"", _x, _y));\
|
|
} while(0)
|
|
#define AssertStrEQ(x, y) AssertStr(x, y, ==, !=)
|
|
#define AssertStrNE(x, y) AssertStr(x, y, !=, ==)
|
|
#define AssertStrGT(x, y) AssertStr(x, y, >, <=)
|
|
#define AssertStrLT(x, y) AssertStr(x, y, <, >=)
|
|
#define AssertStrGE(x, y) AssertStr(x, y, >=, <)
|
|
#define AssertStrLE(x, y) AssertStr(x, y, <=, >)
|
|
|
|
#ifndef WOLFTPM2_NO_WRAPPER
|
|
|
|
static void test_wolfTPM2_Init(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
|
|
/* Test first argument, wolfTPM2 context */
|
|
rc = wolfTPM2_Init(NULL, TPM2_IoCb, NULL);
|
|
AssertIntNE(rc, 0);
|
|
/* Test second argument, TPM2 IO Callbacks */
|
|
rc = wolfTPM2_Init(&dev, NULL, NULL);
|
|
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || defined(WOLFTPM_WINAPI)
|
|
/* Custom IO Callbacks are not needed for Linux TIS driver */
|
|
AssertIntEQ(rc, 0);
|
|
#else
|
|
/* IO Callbacks are required for SPIdev/I2C and must be valid */
|
|
AssertIntNE(rc, 0);
|
|
#endif
|
|
|
|
/* Test success */
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
wolfTPM2_Cleanup(&dev);
|
|
|
|
printf("Test TPM Wrapper:\tInit:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
|
|
/* test for WOLFTPM2_DEV restore */
|
|
static void test_wolfTPM2_OpenExisting(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
WOLFTPM2_CAPS caps;
|
|
|
|
/* Init the TPM2 device */
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test access to TPM by getting capabilities */
|
|
rc = wolfTPM2_GetCapabilities(&dev, &caps);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Perform cleanup, but don't shutdown TPM module */
|
|
rc = wolfTPM2_Cleanup_ex(&dev, 0);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
|
|
/* Restore TPM access */
|
|
rc = wolfTPM2_OpenExisting(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test access to TPM by getting capabilities */
|
|
rc = wolfTPM2_GetCapabilities(&dev, &caps);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
wolfTPM2_Cleanup(&dev);
|
|
|
|
printf("Test TPM Wrapper:\tOpen Existing:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
/* test for wolfTPM2_GetCapabilities */
|
|
static void test_wolfTPM2_GetCapabilities(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
WOLFTPM2_CAPS caps;
|
|
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test Arguments */
|
|
rc = wolfTPM2_GetCapabilities(NULL, &caps);
|
|
AssertIntNE(rc, 0);
|
|
rc = wolfTPM2_GetCapabilities(&dev, NULL);
|
|
AssertIntNE(rc, 0);
|
|
|
|
/* Test success */
|
|
rc = wolfTPM2_GetCapabilities(&dev, &caps);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
#ifdef DEBUG_WOLFTPM
|
|
printf("Mfg %s (%d), Vendor %s, Fw %u.%u (%u), FIPS 140-2 %d, CC-EAL4 %d\n",
|
|
caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor,
|
|
caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4);
|
|
#endif
|
|
|
|
wolfTPM2_Cleanup(&dev);
|
|
|
|
printf("Test TPM Wrapper:\tGet Capabilities:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
/* test for wolfTPM2_ReadPublicKey */
|
|
static void test_wolfTPM2_ReadPublicKey(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
WOLFTPM2_KEY storageKey;
|
|
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test arguments */
|
|
rc = wolfTPM2_ReadPublicKey(NULL, &storageKey, TPM2_DEMO_STORAGE_KEY_HANDLE);
|
|
AssertIntNE(rc, 0);
|
|
rc = wolfTPM2_ReadPublicKey(&dev, NULL, TPM2_DEMO_STORAGE_KEY_HANDLE);
|
|
AssertIntNE(rc, 0);
|
|
|
|
/* Test success: read storage primary key */
|
|
rc = wolfTPM2_ReadPublicKey(&dev, &storageKey,
|
|
TPM2_DEMO_STORAGE_KEY_HANDLE);
|
|
if ((rc & RC_MAX_FMT1) == TPM_RC_HANDLE) {
|
|
rc = 0; /* okay if not found */
|
|
}
|
|
AssertIntEQ(rc, 0);
|
|
wolfTPM2_Cleanup(&dev);
|
|
|
|
printf("Test TPM Wrapper:\tRead Public Key:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
static void test_wolfTPM2_GetRandom(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
WOLFTPM2_BUFFER rngData;
|
|
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test arguments */
|
|
rc = wolfTPM2_GetRandom(NULL, rngData.buffer, sizeof(rngData.buffer));
|
|
AssertIntNE(rc, 0);
|
|
rc = wolfTPM2_GetRandom(&dev, NULL, sizeof(rngData.buffer));
|
|
AssertIntNE(rc, 0);
|
|
rc = wolfTPM2_GetRandom(&dev, rngData.buffer, 0);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* Test success */
|
|
rc = wolfTPM2_GetRandom(&dev, rngData.buffer, sizeof(rngData.buffer));
|
|
|
|
AssertIntEQ(rc, 0);
|
|
wolfTPM2_Cleanup(&dev);
|
|
|
|
printf("Test TPM Wrapper:\tGet Random:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
static void test_wolfTPM2_Cleanup(void)
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
|
|
/* Test arguments */
|
|
rc = wolfTPM2_Cleanup(NULL);
|
|
AssertIntNE(rc, 0);
|
|
|
|
/* Test success */
|
|
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
rc = wolfTPM2_Cleanup(&dev);
|
|
AssertIntEQ(rc, 0);
|
|
|
|
printf("Test TPM Wrapper:\tCleanup:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
static void test_TPM2_KDFa(void)
|
|
{
|
|
int rc;
|
|
#define TEST_KDFA_KEYSZ 20
|
|
TPM2B_DATA keyIn = {
|
|
.size = TEST_KDFA_KEYSZ,
|
|
.buffer = {0x27, 0x1F, 0xA0, 0x8B, 0xBD, 0xC5, 0x06, 0x0E, 0xC3, 0xDF,
|
|
0xA9, 0x28, 0xFF, 0x9B, 0x73, 0x12, 0x3A, 0x12, 0xDA, 0x0C}
|
|
};
|
|
const char label[] = "KDFSELFTESTLABEL";
|
|
TPM2B_NONCE contextU = {
|
|
.size = 8,
|
|
.buffer = {0xCE, 0x24, 0x4F, 0x39, 0x5D, 0xCA, 0x73, 0x91}
|
|
};
|
|
TPM2B_NONCE contextV = {
|
|
.size = 8,
|
|
.buffer = {0xDA, 0x50, 0x40, 0x31, 0xDD, 0xF1, 0x2E, 0x83}
|
|
};
|
|
byte key[TEST_KDFA_KEYSZ];
|
|
|
|
#ifndef WOLFTPM2_NO_WOLFCRYPT
|
|
const byte keyExp[TEST_KDFA_KEYSZ] = {
|
|
0xbb, 0x02, 0x59, 0xe1, 0xc8, 0xba, 0x60, 0x7e, 0x6a, 0x2c,
|
|
0xd7, 0x04, 0xb6, 0x9a, 0x90, 0x2e, 0x9a, 0xde, 0x84, 0xc4};
|
|
#endif
|
|
|
|
rc = TPM2_KDFa(TPM_ALG_SHA256, &keyIn, label, &contextU, &contextV, key, keyIn.size);
|
|
#ifdef WOLFTPM2_NO_WOLFCRYPT
|
|
AssertIntEQ(NOT_COMPILED_IN, rc);
|
|
#else
|
|
AssertIntEQ(sizeof(keyExp), rc);
|
|
AssertIntEQ(XMEMCMP(key, keyExp, sizeof(keyExp)), 0);
|
|
#endif
|
|
|
|
printf("Test TPM Wrapper:\tKDFa:\t%s\n",
|
|
rc >= 0 ? "Passed" : "Failed");
|
|
}
|
|
|
|
static void test_wolfTPM2_CSR(void)
|
|
{
|
|
#if defined(WOLFTPM2_CERT_GEN) && !defined(WOLFTPM2_NO_HEAP)
|
|
int rc;
|
|
WOLFTPM2_CSR* csr = wolfTPM2_NewCSR();
|
|
AssertNotNull(csr);
|
|
|
|
/* invalid cases */
|
|
rc = wolfTPM2_CSR_SetSubject(NULL, NULL, NULL);
|
|
AssertIntEQ(rc, BAD_FUNC_ARG);
|
|
rc = wolfTPM2_CSR_SetSubject(NULL, csr, NULL);
|
|
AssertIntEQ(rc, BAD_FUNC_ARG);
|
|
|
|
/* valid, but empty DH strings */
|
|
rc = wolfTPM2_CSR_SetSubject(NULL, csr, ""); /* test no slash */
|
|
AssertIntEQ(rc, 0);
|
|
rc = wolfTPM2_CSR_SetSubject(NULL, csr, "/C=/CN="); /* test blank value */
|
|
AssertIntEQ(rc, 0);
|
|
|
|
/* valid string */
|
|
rc = wolfTPM2_CSR_SetSubject(NULL, csr,
|
|
"/C=US/ST=Oregon/L=Portland/SN=Test/O=wolfSSL"
|
|
"/OU=RSA/CN=www.wolfssl.com/emailAddress=info@wolfssl.com");
|
|
AssertIntEQ(rc, 0);
|
|
|
|
wolfTPM2_FreeCSR(csr);
|
|
|
|
printf("Test TPM Wrapper:\tCSR Subject:\t%s\n",
|
|
rc == 0 ? "Passed" : "Failed");
|
|
#endif
|
|
}
|
|
|
|
#if defined(HAVE_THREAD_LS) && defined(HAVE_PTHREAD)
|
|
#include <pthread.h>
|
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
int secondRunner = 0;
|
|
|
|
static void test_wolfTPM2_thread_local_storage_work_thread(void* args)
|
|
{
|
|
TPM2_CTX tpm2Ctx;
|
|
|
|
TPM2_Init(&tpm2Ctx, NULL, NULL);
|
|
|
|
/* lock so that the other thread must wait while we set the ctx */
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
/* ctx should be what was set in init, not set by other thread */
|
|
if (secondRunner == 1) {
|
|
if (TPM2_GetActiveCtx() != &tpm2Ctx)
|
|
printf("Test TPM Wrapper:\tThread Local Storage\tFailed\n");
|
|
else
|
|
printf("Test TPM Wrapper:\tThread Local Storage\tPassed\n");
|
|
}
|
|
|
|
/* set the active ctx, should not impact the other thread */
|
|
TPM2_SetActiveCtx(&tpm2Ctx);
|
|
|
|
secondRunner = 1;
|
|
|
|
/* let the other thread run */
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
(void)args;
|
|
}
|
|
#endif /* HAVE_THREAD_LS && HAVE_PTHREAD */
|
|
|
|
static void test_wolfTPM2_thread_local_storage(void)
|
|
{
|
|
#if defined(HAVE_THREAD_LS) && defined(HAVE_PTHREAD)
|
|
pthread_t thread_1;
|
|
pthread_t thread_2;
|
|
|
|
pthread_create(&thread_1, NULL,
|
|
(void*)&test_wolfTPM2_thread_local_storage_work_thread, NULL);
|
|
pthread_create(&thread_2, NULL,
|
|
(void*)&test_wolfTPM2_thread_local_storage_work_thread, NULL);
|
|
|
|
pthread_join(thread_1, NULL);
|
|
pthread_join(thread_2, NULL);
|
|
#endif /* HAVE_THREAD_LS && HAVE_PTHREAD */
|
|
}
|
|
|
|
#endif /* !WOLFTPM2_NO_WRAPPER */
|
|
|
|
#ifndef NO_MAIN_DRIVER
|
|
int main(int argc, char *argv[])
|
|
#else
|
|
int unit_tests(int argc, char *argv[])
|
|
#endif
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
#ifndef WOLFTPM2_NO_WRAPPER
|
|
test_wolfTPM2_Init();
|
|
test_wolfTPM2_OpenExisting();
|
|
test_wolfTPM2_GetCapabilities();
|
|
test_wolfTPM2_GetRandom();
|
|
test_TPM2_KDFa();
|
|
test_wolfTPM2_ReadPublicKey();
|
|
test_wolfTPM2_CSR();
|
|
test_wolfTPM2_Cleanup();
|
|
test_wolfTPM2_thread_local_storage();
|
|
#endif /* !WOLFTPM2_NO_WRAPPER */
|
|
|
|
return 0;
|
|
}
|