diff --git a/.gitignore b/.gitignore index 3f875239..5d98b803 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ build/ examples/wrap/wrap_test examples/wrap/caps +examples/wrap/hmac examples/native/native_test examples/bench/bench examples/csr/csr diff --git a/examples/run_examples.sh b/examples/run_examples.sh index a1e8576d..8b4cebca 100755 --- a/examples/run_examples.sh +++ b/examples/run_examples.sh @@ -136,6 +136,38 @@ if [ $WOLFCRYPT_ENABLE -eq 1 ]; then [ $RESULT -ne 0 ] && echo -e "wrap_test (AES param enc) failed! $RESULT" && exit 1 fi +# HMAC tests +echo -e "HMAC tests" +./examples/wrap/hmac >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hmac test failed! $RESULT" && exit 1 +./examples/wrap/hmac -ecc >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hmac test (ECC SRK) failed! $RESULT" && exit 1 +./examples/wrap/hmac -rsa >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hmac test (RSA SRK) failed! $RESULT" && exit 1 +if [ $WOLFCRYPT_ENABLE -eq 1 ]; then + ./examples/wrap/hmac -aes >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "hmac test (AES param enc) failed! $RESULT" && exit 1 +fi +if [ $WOLFCRYPT_ENABLE -eq 1 ]; then + ./examples/wrap/hmac -xor >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "hmac test (XOR param enc) failed! $RESULT" && exit 1 +fi +if [ $WOLFCRYPT_ENABLE -eq 1 ]; then + ./examples/wrap/hmac -rsa -aes >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "hmac test (RSA SRK + AES param enc) failed! $RESULT" && exit 1 +fi +if [ $WOLFCRYPT_ENABLE -eq 1 ]; then + ./examples/wrap/hmac -ecc -xor >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "hmac test (ECC SRK + XOR param enc) failed! $RESULT" && exit 1 +fi + # Key Generation Tests echo -e "Key Generation Tests" diff --git a/examples/tpm_test.h b/examples/tpm_test.h index 51d9c5df..ff9640b5 100644 --- a/examples/tpm_test.h +++ b/examples/tpm_test.h @@ -33,6 +33,7 @@ #define TPM2_DEMO_STORAGE_KEY_HANDLE 0x81000200 /* Persistent Storage Key Handle (RSA) */ #define TPM2_DEMO_STORAGE_EC_KEY_HANDLE 0x81000201 /* Persistent Storage Key Handle (ECC) */ #define TPM2_DEMO_PERSISTENT_KEY_HANDLE 0x81000202 /* Persistent Key Handle for common use */ +#define TPM2_DEMO_HMAC_KEY_HANDLE 0x81000210 /* Persistent HMAC Key Handle */ #define TPM2_DEMO_RSA_IDX 0x20 /* offset handle to unused index */ #define TPM2_DEMO_RSA_KEY_HANDLE (0x81000000 + TPM2_DEMO_RSA_IDX) /* Persistent Key Handle */ #define TPM2_DEMO_RSA_CERT_HANDLE (0x01800000 + TPM2_DEMO_RSA_IDX) /* NV Handle */ diff --git a/examples/wrap/hmac.c b/examples/wrap/hmac.c new file mode 100644 index 00000000..28ecd92d --- /dev/null +++ b/examples/wrap/hmac.c @@ -0,0 +1,242 @@ +/* hmac.c + * + * Copyright (C) 2006-2025 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 + */ + +/* This example shows using the TPM2 wrapper API's for HMAC + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include +#include + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include +#include + +static void usage(void) +{ + printf("Expected Usage:\n"); + printf("./examples/wrap/hmac [-aes/xor] [-rsa/ecc]\n"); + printf("* -aes/xor: Use Parameter Encryption\n"); + printf("* -rsa/ecc: Use RSA or ECC for SRK (default ECC)\n"); + printf("* -keep: Keep the HMAC key in persistent storage\n"); + printf("\nThis example demonstrates:\n"); + printf("1. Creating an SRK (Storage Root Key)\n"); + printf("2. Loading an HMAC key using the SRK as parent\n"); + printf("3. Storing the HMAC key persistently at handle 0x%x\n", + TPM2_DEMO_HMAC_KEY_HANDLE); + printf("4. Using the persistent HMAC key for HMAC operations\n"); + printf("5. Reusing the persistent key for multiple operations\n\n"); +} + +int TPM2_Wrapper_Hmac(void* userCtx) +{ + return TPM2_Wrapper_HmacArgs(userCtx, 0, NULL); +} +int TPM2_Wrapper_HmacArgs(void* userCtx, int argc, char *argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY storage; /* SRK */ + WOLFTPM2_HMAC hmac; + WOLFTPM2_SESSION tpmSession; + TPMI_ALG_PUBLIC srkAlg = TPM_ALG_ECC; /* prefer ECC, but allow RSA */ + TPM_ALG_ID paramEncAlg = TPM_ALG_NULL; + WOLFTPM2_BUFFER cipher; + int keepKey = 0; + + const char* hmacTestKey = + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b"; + const char* hmacTestData = "Hi There"; + const char* hmacTestDig = + "\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b" + "\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7"; + + if (argc >= 2) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + while (argc > 1) { + if (XSTRCMP(argv[argc-1], "-rsa") == 0) { + srkAlg = TPM_ALG_RSA; + } + else if (XSTRCMP(argv[argc-1], "-ecc") == 0) { + srkAlg = TPM_ALG_ECC; + } + else if (XSTRCMP(argv[argc-1], "-aes") == 0) { + paramEncAlg = TPM_ALG_CFB; + } + else if (XSTRCMP(argv[argc-1], "-xor") == 0) { + paramEncAlg = TPM_ALG_XOR; + } + else if (XSTRCMP(argv[argc-1], "-keep") == 0) { + keepKey = 1; + } + else { + printf("Warning: Unrecognized option: %s\n", argv[argc-1]); + } + + argc--; + } + + XMEMSET(&hmac, 0, sizeof(hmac)); + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); + + printf("TPM2.0 HMAC example\n"); + printf("\tUse Parameter Encryption: %s\n", TPM2_GetAlgName(paramEncAlg)); + printf("\tSRK: %s\n", TPM2_GetAlgName(srkAlg)); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != 0) goto exit; + + /* storage root key (SRK) */ + rc = getPrimaryStoragekey(&dev, &storage, srkAlg); + if (rc != 0) goto exit; + + /* Start an authenticated session (salted / unbound) with parameter encryption */ + if (paramEncAlg != TPM_ALG_NULL) { + WOLFTPM2_KEY* bindKey = &storage; + #ifdef NO_RSA + if (srkAlg == TPM_ALG_RSA) + bindKey = NULL; /* cannot bind to key without RSA enabled */ + #endif + #ifndef HAVE_ECC + if (srkAlg == TPM_ALG_ECC) + bindKey = NULL; /* cannot bind to key without ECC enabled */ + #endif + rc = wolfTPM2_StartSession(&dev, &tpmSession, bindKey, NULL, + TPM_SE_HMAC, paramEncAlg); + if (rc != 0) goto exit; + printf("TPM2_StartAuthSession: sessionHandle 0x%x\n", + (word32)tpmSession.handle.hndl); + + /* set session for authorization of the storage key */ + rc = wolfTPM2_SetAuthSession(&dev, 0, &tpmSession, + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | TPMA_SESSION_continueSession)); + if (rc != 0) goto exit; + } + + /* Try to load existing persistent HMAC key first */ + rc = wolfTPM2_ReadPublicKey(&dev, &hmac.key, TPM2_DEMO_HMAC_KEY_HANDLE); + if (rc != 0) { + printf("Persistent HMAC key not found, creating new one...\n"); + + /* Load Keyed Hash Key */ + rc = wolfTPM2_LoadKeyedHashKey(&dev, &hmac.key, &storage.handle, + TPM_ALG_SHA256, + (const byte*)hmacTestKey, (word32)XSTRLEN(hmacTestKey), + (const byte*)gUsageAuth, sizeof(gUsageAuth)-1); + if (rc != 0) goto exit; + + printf("Storing HMAC key to persistent handle 0x%x\n", TPM2_DEMO_HMAC_KEY_HANDLE); + /* Store the HMAC key to persistent storage */ + rc = wolfTPM2_NVStoreKey(&dev, TPM_RH_OWNER, &hmac.key, + TPM2_DEMO_HMAC_KEY_HANDLE); + if (rc != 0) { + printf("wolfTPM2_NVStoreKey failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + printf("HMAC key stored persistently at handle 0x%x\n", + TPM2_DEMO_HMAC_KEY_HANDLE); + } + else { + printf("Using existing persistent HMAC key at handle 0x%x\n", + TPM2_DEMO_HMAC_KEY_HANDLE); + + /* Set auth for persistent key */ + hmac.key.handle.auth.size = sizeof(gUsageAuth)-1; + XMEMCPY(hmac.key.handle.auth.buffer, gUsageAuth, + hmac.key.handle.auth.size); + } + + /* Test HMAC operations using the persistent key */ + printf("\nTesting HMAC operations with persistent key...\n"); + + hmac.hmacKeyKeep = 1; /* don't unload key on finish */ + rc = wolfTPM2_HmacStart(&dev, &hmac, &storage.handle, TPM_ALG_SHA256, + NULL, 0, (const byte*)gUsageAuth, sizeof(gUsageAuth)-1); + if (rc != 0) goto exit; + + rc = wolfTPM2_HmacUpdate(&dev, &hmac, (byte*)hmacTestData, + (word32)XSTRLEN(hmacTestData)); + if (rc != 0) goto exit; + + cipher.size = TPM_SHA256_DIGEST_SIZE; + rc = wolfTPM2_HmacFinish(&dev, &hmac, cipher.buffer, (word32*)&cipher.size); + if (rc != 0) goto exit; + + if (cipher.size != TPM_SHA256_DIGEST_SIZE || + XMEMCMP(cipher.buffer, hmacTestDig, cipher.size) != 0) { + printf("HMAC SHA256 test failed, result not as expected!\n"); + goto exit; + } + printf("HMAC SHA256 test with persistent key: PASSED\n"); + + if (!keepKey) { + /* remove the key from persistent storage */ + wolfTPM2_SetAuthPassword(&dev, 0, NULL); + wolfTPM2_NVDeleteKey(&dev, TPM_RH_OWNER, &hmac.key); + } + +exit: + if (rc != 0) { + printf("\nFailure 0x%x: %s\n\n", rc, wolfTPM2_GetRCString(rc)); + } + + /* Clean up session */ + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); + wolfTPM2_UnloadHandle(&dev, &hmac.key.handle); + + wolfTPM2_Cleanup(&dev); + return rc; +} + +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char *argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_Wrapper_HmacArgs(NULL, argc, argv); +#else + (void)argc; + (void)argv; + printf("Wrapper code not compiled in\n"); +#endif + + return rc; +} +#endif /* !NO_MAIN_DRIVER */ diff --git a/examples/wrap/include.am b/examples/wrap/include.am index a3ddfc1b..bc517449 100644 --- a/examples/wrap/include.am +++ b/examples/wrap/include.am @@ -3,8 +3,10 @@ if BUILD_EXAMPLES noinst_PROGRAMS += examples/wrap/wrap_test \ - examples/wrap/caps + examples/wrap/caps \ + examples/wrap/hmac noinst_HEADERS += examples/wrap/wrap_test.h + examples_wrap_wrap_test_SOURCES = examples/wrap/wrap_test.c examples_wrap_wrap_test_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) examples_wrap_wrap_test_DEPENDENCIES = src/libwolftpm.la @@ -12,11 +14,18 @@ examples_wrap_wrap_test_DEPENDENCIES = src/libwolftpm.la examples_wrap_caps_SOURCES = examples/wrap/caps.c examples_wrap_caps_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) examples_wrap_caps_DEPENDENCIES = src/libwolftpm.la + +examples_wrap_hmac_SOURCES = examples/wrap/hmac.c \ + examples/tpm_test_keys.c +examples_wrap_hmac_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_wrap_hmac_DEPENDENCIES = src/libwolftpm.la endif example_wrapdir = $(exampledir)/wrap dist_example_wrap_DATA = examples/wrap/wrap_test.c \ - examples/wrap/caps.c + examples/wrap/caps.c \ + examples/wrap/hmac.c DISTCLEANFILES+= examples/wrap/.libs/wrap_test \ - examples/wrap/.libs/caps + examples/wrap/.libs/caps \ + examples/wrap/.libs/hmac diff --git a/examples/wrap/wrap_test.h b/examples/wrap/wrap_test.h index 35bdd04c..e41a2139 100644 --- a/examples/wrap/wrap_test.h +++ b/examples/wrap/wrap_test.h @@ -32,6 +32,9 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[]); int TPM2_Wrapper_Caps(void* userCtx); int TPM2_Wrapper_CapsArgs(void* userCtx, int argc, char *argv[]); +int TPM2_Wrapper_Hmac(void* userCtx); +int TPM2_Wrapper_HmacArgs(void* userCtx, int argc, char *argv[]); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ad6e1741..590c7b9e 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -5630,18 +5630,22 @@ int wolfTPM2_HmacStart(WOLFTPM2_DEV* dev, WOLFTPM2_HMAC* hmac, return BAD_FUNC_ARG; } - /* Capture usage auth */ - if (usageAuthSz > sizeof(hmac->hash.handle.auth.buffer)) - usageAuthSz = sizeof(hmac->hash.handle.auth.buffer); - hmac->hash.handle.auth.size = usageAuthSz; - XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz); - - if (!hmac->hmacKeyLoaded || hmac->key.handle.hndl == TPM_RH_NULL) { - /* Load Keyed Hash Key */ - rc = wolfTPM2_LoadKeyedHashKey(dev, &hmac->key, parent, hashAlg, keyBuf, - keySz, usageAuth, usageAuthSz); - if (rc != 0) { - return rc; + if (usageAuth != NULL) { + /* Capture usage auth */ + if (usageAuthSz > sizeof(hmac->hash.handle.auth.buffer)) + usageAuthSz = sizeof(hmac->hash.handle.auth.buffer); + hmac->hash.handle.auth.size = usageAuthSz; + XMEMCPY(hmac->hash.handle.auth.buffer, usageAuth, usageAuthSz); + } + + if (!hmac->hmacKeyLoaded) { + if (hmac->key.handle.hndl == 0 || hmac->key.handle.hndl == TPM_RH_NULL){ + /* Load Keyed Hash Key */ + rc = wolfTPM2_LoadKeyedHashKey(dev, &hmac->key, parent, hashAlg, + keyBuf, keySz, usageAuth, usageAuthSz); + if (rc != 0) { + return rc; + } } hmac->hmacKeyLoaded = 1; }