From 2794e8aa9f982da3eaa7318c70f0486c2911ab07 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 12:10:51 -0700 Subject: [PATCH 1/5] Add getrandom, hash and AES encrypt/decrypt examples --- examples/wrap/encrypt_decrypt.c | 213 ++++++++++++++++++++++++++++++++ examples/wrap/getrandom.c | 130 +++++++++++++++++++ examples/wrap/hash.c | 164 ++++++++++++++++++++++++ examples/wrap/include.am | 28 ++++- examples/wrap/wrap_test.h | 4 + 5 files changed, 536 insertions(+), 3 deletions(-) create mode 100644 examples/wrap/encrypt_decrypt.c create mode 100644 examples/wrap/getrandom.c create mode 100644 examples/wrap/hash.c diff --git a/examples/wrap/encrypt_decrypt.c b/examples/wrap/encrypt_decrypt.c new file mode 100644 index 00000000..c6db0b09 --- /dev/null +++ b/examples/wrap/encrypt_decrypt.c @@ -0,0 +1,213 @@ +/* encrypt_decrypt.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +/* Example for symmetric encrypt/decrypt using a TPM generated AES key */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include +#include + +#include + +/* Number of message bytes to encrypt/decrypt */ +#define ENCDEC_MSG_SIZE 32 + +/******************************************************************************/ +/* --- BEGIN TPM2 Encrypt/Decrypt example -- */ +/******************************************************************************/ + +static void usage(void) +{ + printf("Expected Usage:\n"); + printf("./examples/wrap/encrypt_decrypt [-aesctr] [-aescbc] [-aescfb]\n"); + printf("* AES mode defaults to CTR; use -aescbc or -aescfb to override\n"); + printf("* NOTE: many TPM's disable TPM2_EncryptDecrypt entirely due to\n"); + printf(" export controls (see examples/tpm_test.h); when enabled\n"); + printf(" the supported mode varies by TPM\n"); +} + +int TPM2_EncryptDecrypt_Example(void* userCtx, int argc, char* argv[]) +{ + int rc; + int i; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY storage; /* SRK */ + WOLFTPM2_KEY aesKey; + TPMT_PUBLIC publicTemplate; + /* TPM2_EncryptDecrypt is frequently disabled entirely due to export + * controls (see comments in examples/tpm_test.h); when enabled the + * supported mode varies by TPM. Default to CTR; -aescbc / -aescfb + * override. A fully disabled command is handled gracefully below. */ + TPM_ALG_ID mode = TPM_ALG_CTR; + const char* modeName = "AES-CTR"; + byte message[ENCDEC_MSG_SIZE]; + byte cipher[ENCDEC_MSG_SIZE]; + byte plain[ENCDEC_MSG_SIZE]; + byte iv[MAX_AES_BLOCK_SIZE_BYTES]; + + if (argc > 1) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "-aesctr") == 0) { + mode = TPM_ALG_CTR; + modeName = "AES-CTR"; + } + else if (XSTRCMP(argv[i], "-aescbc") == 0) { + mode = TPM_ALG_CBC; + modeName = "AES-CBC"; + } + else if (XSTRCMP(argv[i], "-aescfb") == 0) { + mode = TPM_ALG_CFB; + modeName = "AES-CFB"; + } + } + + printf("TPM2 Encrypt/Decrypt Example (%s)\n", modeName); + + XMEMSET(&storage, 0, sizeof(storage)); + XMEMSET(&aesKey, 0, sizeof(aesKey)); + XMEMSET(&publicTemplate, 0, sizeof(publicTemplate)); + + /* Test data */ + for (i = 0; i < (int)sizeof(message); i++) { + message[i] = (byte)(i & 0xff); + } + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(plain, 0, sizeof(plain)); + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != 0) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + return rc; + } + + /* Create or load the Storage Root Key (SRK) */ + rc = getPrimaryStoragekey(&dev, &storage, TPM_ALG_RSA); + if (rc != 0) { + printf("getPrimaryStoragekey failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + /* Create and load a 128-bit symmetric key under the SRK + * (isSign=NO, isDecrypt=YES) */ + rc = wolfTPM2_GetKeyTemplate_Symmetric(&publicTemplate, 128, mode, NO, YES); + if (rc != 0) { + printf("wolfTPM2_GetKeyTemplate_Symmetric failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + rc = wolfTPM2_CreateAndLoadKey(&dev, &aesKey, &storage.handle, + &publicTemplate, (const byte*)gUsageAuth, sizeof(gUsageAuth)-1); + if (rc != 0) { + printf("wolfTPM2_CreateAndLoadKey failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + /* Encrypt */ + XMEMSET(iv, 0, sizeof(iv)); + rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, message, cipher, + (word32)sizeof(message), iv, (word32)sizeof(iv), WOLFTPM2_ENCRYPT); + if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { + printf("wolfTPM2_EncryptDecrypt (encrypt) failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { + printf("Encrypt/Decrypt: not supported (export controls)\n"); + rc = 0; /* not an error condition */ + goto exit; + } + + /* Decrypt */ + XMEMSET(iv, 0, sizeof(iv)); + rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, cipher, plain, + (word32)sizeof(cipher), iv, (word32)sizeof(iv), WOLFTPM2_DECRYPT); + if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { + printf("wolfTPM2_EncryptDecrypt (decrypt) failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { + printf("Encrypt/Decrypt: not supported (export controls)\n"); + rc = 0; /* not an error condition */ + goto exit; + } + + if (XMEMCMP(message, plain, sizeof(message)) != 0) { + printf("Encrypt/Decrypt test failed, result not as expected!\n"); + rc = TPM_RC_TESTING; + goto exit; + } + printf("Encrypt/Decrypt test success\n"); + +exit: + + wolfTPM2_UnloadHandle(&dev, &aesKey.handle); + wolfTPM2_UnloadHandle(&dev, &storage.handle); + + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2 Encrypt/Decrypt example -- */ +/******************************************************************************/ + +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_EncryptDecrypt_Example(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/getrandom.c b/examples/wrap/getrandom.c new file mode 100644 index 00000000..13520592 --- /dev/null +++ b/examples/wrap/getrandom.c @@ -0,0 +1,130 @@ +/* getrandom.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +/* Example for getting random bytes from the TPM */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include + +#include + +/* Default and maximum number of random bytes to request */ +#define GETRANDOM_DEFAULT_BYTES 32 +#define GETRANDOM_MAX_BYTES 256 + +/******************************************************************************/ +/* --- BEGIN TPM2 Get Random example -- */ +/******************************************************************************/ + +static void usage(void) +{ + printf("Expected Usage:\n"); + printf("./examples/wrap/getrandom [bytes]\n"); + printf("* bytes is the number of random bytes to request " + "(default %d, max %d)\n", GETRANDOM_DEFAULT_BYTES, GETRANDOM_MAX_BYTES); +} + +int TPM2_GetRandom_Example(void* userCtx, int argc, char* argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + byte buf[GETRANDOM_MAX_BYTES]; + word32 len = GETRANDOM_DEFAULT_BYTES; + word32 i; + + if (argc > 1) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + len = (word32)XATOI(argv[1]); + if (len == 0) { + len = GETRANDOM_DEFAULT_BYTES; + } + if (len > GETRANDOM_MAX_BYTES) { + len = GETRANDOM_MAX_BYTES; + } + } + + printf("TPM2 Get Random Example (%u bytes)\n", len); + + XMEMSET(buf, 0, sizeof(buf)); + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != 0) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + return rc; + } + + rc = wolfTPM2_GetRandom(&dev, buf, len); + if (rc != 0) { + printf("wolfTPM2_GetRandom failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + printf("Random bytes:\n"); + for (i = 0; i < len; i++) { + printf("%02x", buf[i]); + } + printf("\n"); + +exit: + + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2 Get Random example -- */ +/******************************************************************************/ + +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_GetRandom_Example(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/hash.c b/examples/wrap/hash.c new file mode 100644 index 00000000..66288d3f --- /dev/null +++ b/examples/wrap/hash.c @@ -0,0 +1,164 @@ +/* hash.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +/* Example for computing a hash digest using the TPM hash sequence */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include + +#include + +/******************************************************************************/ +/* --- BEGIN TPM2 Hash example -- */ +/******************************************************************************/ + +static void usage(void) +{ + printf("Expected Usage:\n"); + printf("./examples/wrap/hash [message] [-sha256] [-sha384] [-sha512]\n"); + printf("* message is the string to hash (default is a test vector)\n"); + printf("* hash algorithm defaults to SHA-256\n"); +} + +int TPM2_Hash_Example(void* userCtx, int argc, char* argv[]) +{ + int rc; + int i; + WOLFTPM2_DEV dev; + WOLFTPM2_HASH hash; + TPMI_ALG_HASH hashAlg = TPM_ALG_SHA256; + const char* hashAlgName = "SHA-256"; + byte digest[TPM_MAX_DIGEST_SIZE]; + word32 digestSz = (word32)sizeof(digest); + /* NIST SHA test vector message */ + const char* message = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + + if (argc > 1) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "-sha256") == 0) { + hashAlg = TPM_ALG_SHA256; + hashAlgName = "SHA-256"; + } + #ifdef WOLFSSL_SHA384 + else if (XSTRCMP(argv[i], "-sha384") == 0) { + hashAlg = TPM_ALG_SHA384; + hashAlgName = "SHA-384"; + } + #endif + #ifdef WOLFSSL_SHA512 + else if (XSTRCMP(argv[i], "-sha512") == 0) { + hashAlg = TPM_ALG_SHA512; + hashAlgName = "SHA-512"; + } + #endif + else if (argv[i][0] != '-') { + message = argv[i]; + } + } + + printf("TPM2 Hash Example (%s)\n", hashAlgName); + printf("Message: %s\n", message); + + XMEMSET(&hash, 0, sizeof(hash)); + XMEMSET(digest, 0, sizeof(digest)); + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != 0) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + return rc; + } + + rc = wolfTPM2_HashStart(&dev, &hash, hashAlg, NULL, 0); + if (rc != 0) { + printf("wolfTPM2_HashStart failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + rc = wolfTPM2_HashUpdate(&dev, &hash, (const byte*)message, + (word32)XSTRLEN(message)); + if (rc != 0) { + printf("wolfTPM2_HashUpdate failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + rc = wolfTPM2_HashFinish(&dev, &hash, digest, &digestSz); + if (rc != 0) { + printf("wolfTPM2_HashFinish failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + printf("Digest (%u bytes):\n", digestSz); + for (i = 0; i < (int)digestSz; i++) { + printf("%02x", digest[i]); + } + printf("\n"); + +exit: + + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2 Hash example -- */ +/******************************************************************************/ + +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_Hash_Example(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 bc517449..c40889ab 100644 --- a/examples/wrap/include.am +++ b/examples/wrap/include.am @@ -4,7 +4,10 @@ if BUILD_EXAMPLES noinst_PROGRAMS += examples/wrap/wrap_test \ examples/wrap/caps \ - examples/wrap/hmac + examples/wrap/hmac \ + examples/wrap/getrandom \ + examples/wrap/hash \ + examples/wrap/encrypt_decrypt noinst_HEADERS += examples/wrap/wrap_test.h examples_wrap_wrap_test_SOURCES = examples/wrap/wrap_test.c @@ -19,13 +22,32 @@ 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 + +examples_wrap_getrandom_SOURCES = examples/wrap/getrandom.c +examples_wrap_getrandom_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_wrap_getrandom_DEPENDENCIES = src/libwolftpm.la + +examples_wrap_hash_SOURCES = examples/wrap/hash.c +examples_wrap_hash_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_wrap_hash_DEPENDENCIES = src/libwolftpm.la + +examples_wrap_encrypt_decrypt_SOURCES = examples/wrap/encrypt_decrypt.c \ + examples/tpm_test_keys.c +examples_wrap_encrypt_decrypt_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_wrap_encrypt_decrypt_DEPENDENCIES = src/libwolftpm.la endif example_wrapdir = $(exampledir)/wrap dist_example_wrap_DATA = examples/wrap/wrap_test.c \ examples/wrap/caps.c \ - examples/wrap/hmac.c + examples/wrap/hmac.c \ + examples/wrap/getrandom.c \ + examples/wrap/hash.c \ + examples/wrap/encrypt_decrypt.c DISTCLEANFILES+= examples/wrap/.libs/wrap_test \ examples/wrap/.libs/caps \ - examples/wrap/.libs/hmac + examples/wrap/.libs/hmac \ + examples/wrap/.libs/getrandom \ + examples/wrap/.libs/hash \ + examples/wrap/.libs/encrypt_decrypt diff --git a/examples/wrap/wrap_test.h b/examples/wrap/wrap_test.h index 2fbad9f0..cc0dc244 100644 --- a/examples/wrap/wrap_test.h +++ b/examples/wrap/wrap_test.h @@ -35,6 +35,10 @@ 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[]); +int TPM2_GetRandom_Example(void* userCtx, int argc, char *argv[]); +int TPM2_Hash_Example(void* userCtx, int argc, char *argv[]); +int TPM2_EncryptDecrypt_Example(void* userCtx, int argc, char *argv[]); + #ifdef __cplusplus } /* extern "C" */ #endif From e34a721840eaef55c39d6c6372b198fcb8d7b7f3 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 12:10:51 -0700 Subject: [PATCH 2/5] Add ECDH key agreement example --- examples/keygen/ecdh.c | 173 +++++++++++++++++++++++++++++++++++++ examples/keygen/include.am | 10 ++- examples/keygen/keygen.h | 1 + 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 examples/keygen/ecdh.c diff --git a/examples/keygen/ecdh.c b/examples/keygen/ecdh.c new file mode 100644 index 00000000..245e1ae1 --- /dev/null +++ b/examples/keygen/ecdh.c @@ -0,0 +1,173 @@ +/* ecdh.c + * + * Copyright (C) 2006-2026 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 3 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 + */ + +/* Example for ECDH key agreement (shared secret) using the TPM */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include +#include + +#include + +/******************************************************************************/ +/* --- BEGIN TPM2 ECDH example -- */ +/******************************************************************************/ + +static void usage(void) +{ + printf("Expected Usage:\n"); + printf("./examples/keygen/ecdh\n"); + printf("* Demonstrates ECDH key agreement using NIST P-256\n"); +} + +int TPM2_ECDH_Example(void* userCtx, int argc, char* argv[]) +{ + int rc; +#ifdef HAVE_ECC + int i; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY storage; /* SRK */ + WOLFTPM2_KEY eccKey; + TPMT_PUBLIC publicTemplate; + TPM2B_ECC_POINT pubPoint; /* ephemeral public point from the TPM */ + byte secret[MAX_ECC_BYTES]; + int secretSz = (int)sizeof(secret); + + if (argc > 1) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + + printf("TPM2 ECDH Example\n"); + + XMEMSET(&storage, 0, sizeof(storage)); + XMEMSET(&eccKey, 0, sizeof(eccKey)); + XMEMSET(&publicTemplate, 0, sizeof(publicTemplate)); + XMEMSET(&pubPoint, 0, sizeof(pubPoint)); + XMEMSET(secret, 0, sizeof(secret)); + + /* Init the TPM2 device */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != 0) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + return rc; + } + + /* Create or load the Storage Root Key (SRK) */ + rc = getPrimaryStoragekey(&dev, &storage, TPM_ALG_ECC); + if (rc != 0) { + printf("getPrimaryStoragekey failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + /* Create and load an ECC key for key-agreement (ECDH) under the SRK */ + rc = wolfTPM2_GetKeyTemplate_ECC(&publicTemplate, + TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | + TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA, + TPM_ECC_NIST_P256, TPM_ALG_ECDH); + if (rc != 0) { + printf("wolfTPM2_GetKeyTemplate_ECC failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + publicTemplate.nameAlg = TPM_ALG_SHA256; /* make sure its SHA256 */ + + rc = wolfTPM2_CreateAndLoadKey(&dev, &eccKey, &storage.handle, + &publicTemplate, (const byte*)gKeyAuth, sizeof(gKeyAuth)-1); + if (rc != 0) { + printf("wolfTPM2_CreateAndLoadKey failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + /* Generate an ephemeral point and compute the shared secret Z. + * The TPM returns the ephemeral public point (pubPoint) that the peer + * would use to compute the same secret. */ + rc = wolfTPM2_ECDHGen(&dev, &eccKey, &pubPoint, secret, &secretSz); + if (rc != 0) { + printf("wolfTPM2_ECDHGen failed 0x%x: %s\n", rc, + wolfTPM2_GetRCString(rc)); + goto exit; + } + + printf("ECDH key agreement success\n"); + printf("Ephemeral point: X size %u, Y size %u\n", + pubPoint.point.x.size, pubPoint.point.y.size); + printf("Shared secret Z (%d bytes):\n", secretSz); + for (i = 0; i < secretSz; i++) { + printf("%02x", secret[i]); + } + printf("\n"); + +exit: + + wolfTPM2_UnloadHandle(&dev, &eccKey.handle); + wolfTPM2_UnloadHandle(&dev, &storage.handle); + + wolfTPM2_Cleanup(&dev); + +#else + (void)userCtx; + (void)argc; + (void)argv; + printf("ECDH example: not supported (HAVE_ECC not defined)\n"); + rc = 0; +#endif /* HAVE_ECC */ + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2 ECDH example -- */ +/******************************************************************************/ + +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char* argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_ECDH_Example(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/keygen/include.am b/examples/keygen/include.am index 0d0e20b5..b268f559 100644 --- a/examples/keygen/include.am +++ b/examples/keygen/include.am @@ -33,6 +33,12 @@ examples_keygen_external_import_SOURCES = examples/keygen/external_import.c examples/tpm_test_keys.c examples_keygen_external_import_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) examples_keygen_external_import_DEPENDENCIES = src/libwolftpm.la + +noinst_PROGRAMS += examples/keygen/ecdh +examples_keygen_ecdh_SOURCES = examples/keygen/ecdh.c \ + examples/tpm_test_keys.c +examples_keygen_ecdh_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_keygen_ecdh_DEPENDENCIES = src/libwolftpm.la endif example_keygendir = $(exampledir)/keygen @@ -41,10 +47,12 @@ dist_example_keygen_DATA = \ examples/keygen/keyload.c \ examples/keygen/keygen.c \ examples/keygen/keyimport.c \ - examples/keygen/external_import.c + examples/keygen/external_import.c \ + examples/keygen/ecdh.c DISTCLEANFILES+= examples/keygen/.libs/create_primary DISTCLEANFILES+= examples/keygen/.libs/keyload DISTCLEANFILES+= examples/keygen/.libs/keygen DISTCLEANFILES+= examples/keygen/.libs/keyimport DISTCLEANFILES+= examples/keygen/.libs/external_import +DISTCLEANFILES+= examples/keygen/.libs/ecdh diff --git a/examples/keygen/keygen.h b/examples/keygen/keygen.h index ac19be1f..ed518f2d 100644 --- a/examples/keygen/keygen.h +++ b/examples/keygen/keygen.h @@ -31,6 +31,7 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]); int TPM2_Keyload_Example(void* userCtx, int argc, char *argv[]); int TPM2_Keyimport_Example(void* userCtx, int argc, char *argv[]); int TPM2_ExternalImport_Example(void* userCtx, int argc, char *argv[]); +int TPM2_ECDH_Example(void* userCtx, int argc, char *argv[]); #ifdef __cplusplus } /* extern "C" */ From b5f434868084cc07ba79278e8c1614b3bc1cc56e Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 12:13:15 -0700 Subject: [PATCH 3/5] Document new crypto primitive examples --- examples/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/README.md b/examples/README.md index cc3601b2..a801436e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -24,6 +24,16 @@ Demonstrates calling the wolfTPM2_* wrapper API's. `./examples/wrap/wrap_test` +## Crypto Primitive Examples + +Small focused examples for common TPM crypto operations: + +* `./examples/wrap/getrandom [bytes]` - get random bytes from the TPM RNG (default 32). +* `./examples/wrap/hash` - hash a message with a TPM hash sequence (SHA-256 default, `-sha384`/`-sha512`). +* `./examples/wrap/encrypt_decrypt [-aesctr|-aescbc|-aescfb]` - symmetric encrypt/decrypt round-trip (AES-CTR default). Many TPMs disable TPM2_EncryptDecrypt entirely due to export controls; the example skips gracefully when it is unavailable. +* `./examples/keygen/ecdh` - ECDH (P-256) key agreement producing a shared secret. + + ## Attestation Use Cases ### TPM signed timestamp, TPM2.0 GetTime From fb101415aaf5fa013e67b128d82dde426e1f632c Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 12:33:34 -0700 Subject: [PATCH 4/5] Exercise new crypto primitive examples in run_examples.sh --- examples/run_examples.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/examples/run_examples.sh b/examples/run_examples.sh index 00ef0d0c..3aa632d5 100755 --- a/examples/run_examples.sh +++ b/examples/run_examples.sh @@ -194,6 +194,38 @@ if [ $WOLFCRYPT_ENABLE -eq 1 ]; then [ $RESULT -ne 0 ] && echo -e "wrap_test (AES param enc) failed! $RESULT" && exit 1 fi +# Crypto primitive tests +echo -e "Crypto primitive tests" +./examples/wrap/getrandom >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "getrandom failed! $RESULT" && exit 1 +./examples/wrap/getrandom 16 >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "getrandom (16) failed! $RESULT" && exit 1 +./examples/wrap/hash >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hash failed! $RESULT" && exit 1 +./examples/wrap/hash -sha384 >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hash (SHA-384) failed! $RESULT" && exit 1 +./examples/wrap/hash -sha512 >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "hash (SHA-512) failed! $RESULT" && exit 1 +./examples/wrap/encrypt_decrypt >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CTR) failed! $RESULT" && exit 1 +./examples/wrap/encrypt_decrypt -aescbc >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CBC) failed! $RESULT" && exit 1 +./examples/wrap/encrypt_decrypt -aescfb >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CFB) failed! $RESULT" && exit 1 +if [ $WOLFCRYPT_ECC -eq 1 ]; then + ./examples/keygen/ecdh >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "ecdh failed! $RESULT" && exit 1 +fi + # HMAC tests echo -e "HMAC tests" ./examples/wrap/hmac >> $TPMPWD/run.out 2>&1 From 092b9f161864ae0528a02ff823bc53a333676d31 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 12:48:38 -0700 Subject: [PATCH 5/5] Fix new examples for no-ecc/no-rsa and EncryptDecrypt key attributes --- examples/keygen/ecdh.c | 2 ++ examples/run_examples.sh | 10 +++++----- examples/wrap/encrypt_decrypt.c | 25 ++++++++++++++++--------- examples/wrap/hash.c | 19 +++++++++++++++---- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/examples/keygen/ecdh.c b/examples/keygen/ecdh.c index 245e1ae1..008b34e0 100644 --- a/examples/keygen/ecdh.c +++ b/examples/keygen/ecdh.c @@ -40,12 +40,14 @@ /* --- BEGIN TPM2 ECDH example -- */ /******************************************************************************/ +#ifdef HAVE_ECC static void usage(void) { printf("Expected Usage:\n"); printf("./examples/keygen/ecdh\n"); printf("* Demonstrates ECDH key agreement using NIST P-256\n"); } +#endif int TPM2_ECDH_Example(void* userCtx, int argc, char* argv[]) { diff --git a/examples/run_examples.sh b/examples/run_examples.sh index 3aa632d5..25b18475 100755 --- a/examples/run_examples.sh +++ b/examples/run_examples.sh @@ -213,13 +213,13 @@ RESULT=$? [ $RESULT -ne 0 ] && echo -e "hash (SHA-512) failed! $RESULT" && exit 1 ./examples/wrap/encrypt_decrypt >> $TPMPWD/run.out 2>&1 RESULT=$? -[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CTR) failed! $RESULT" && exit 1 -./examples/wrap/encrypt_decrypt -aescbc >> $TPMPWD/run.out 2>&1 +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CFB) failed! $RESULT" && exit 1 +./examples/wrap/encrypt_decrypt -aesctr >> $TPMPWD/run.out 2>&1 RESULT=$? -[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CBC) failed! $RESULT" && exit 1 -./examples/wrap/encrypt_decrypt -aescfb >> $TPMPWD/run.out 2>&1 +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CTR) not supported, skipping ($RESULT)" +./examples/wrap/encrypt_decrypt -aescbc >> $TPMPWD/run.out 2>&1 RESULT=$? -[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CFB) failed! $RESULT" && exit 1 +[ $RESULT -ne 0 ] && echo -e "encrypt_decrypt (AES-CBC) not supported, skipping ($RESULT)" if [ $WOLFCRYPT_ECC -eq 1 ]; then ./examples/keygen/ecdh >> $TPMPWD/run.out 2>&1 RESULT=$? diff --git a/examples/wrap/encrypt_decrypt.c b/examples/wrap/encrypt_decrypt.c index c6db0b09..7f7ef84e 100644 --- a/examples/wrap/encrypt_decrypt.c +++ b/examples/wrap/encrypt_decrypt.c @@ -46,8 +46,8 @@ static void usage(void) { printf("Expected Usage:\n"); - printf("./examples/wrap/encrypt_decrypt [-aesctr] [-aescbc] [-aescfb]\n"); - printf("* AES mode defaults to CTR; use -aescbc or -aescfb to override\n"); + printf("./examples/wrap/encrypt_decrypt [-aescfb] [-aesctr] [-aescbc]\n"); + printf("* AES mode defaults to CFB; use -aesctr or -aescbc to override\n"); printf("* NOTE: many TPM's disable TPM2_EncryptDecrypt entirely due to\n"); printf(" export controls (see examples/tpm_test.h); when enabled\n"); printf(" the supported mode varies by TPM\n"); @@ -63,10 +63,12 @@ int TPM2_EncryptDecrypt_Example(void* userCtx, int argc, char* argv[]) TPMT_PUBLIC publicTemplate; /* TPM2_EncryptDecrypt is frequently disabled entirely due to export * controls (see comments in examples/tpm_test.h); when enabled the - * supported mode varies by TPM. Default to CTR; -aescbc / -aescfb - * override. A fully disabled command is handled gracefully below. */ - TPM_ALG_ID mode = TPM_ALG_CTR; - const char* modeName = "AES-CTR"; + * supported mode varies by TPM. Default to CFB, the mode guaranteed + * when EncryptDecrypt is enabled (matches TEST_AES_MODE in + * examples/tpm_test.h); -aesctr / -aescbc override. A fully disabled + * command is handled gracefully below. */ + TPM_ALG_ID mode = TPM_ALG_CFB; + const char* modeName = "AES-CFB"; byte message[ENCDEC_MSG_SIZE]; byte cipher[ENCDEC_MSG_SIZE]; byte plain[ENCDEC_MSG_SIZE]; @@ -117,16 +119,21 @@ int TPM2_EncryptDecrypt_Example(void* userCtx, int argc, char* argv[]) } /* Create or load the Storage Root Key (SRK) */ +#ifdef NO_RSA + rc = getPrimaryStoragekey(&dev, &storage, TPM_ALG_ECC); +#else rc = getPrimaryStoragekey(&dev, &storage, TPM_ALG_RSA); +#endif if (rc != 0) { printf("getPrimaryStoragekey failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc)); goto exit; } - /* Create and load a 128-bit symmetric key under the SRK - * (isSign=NO, isDecrypt=YES) */ - rc = wolfTPM2_GetKeyTemplate_Symmetric(&publicTemplate, 128, mode, NO, YES); + /* Create and load a 128-bit symmetric key under the SRK. Both sign + * (encrypt) and decrypt attributes are required so the same key can be + * used in both EncryptDecrypt directions. */ + rc = wolfTPM2_GetKeyTemplate_Symmetric(&publicTemplate, 128, mode, YES, YES); if (rc != 0) { printf("wolfTPM2_GetKeyTemplate_Symmetric failed 0x%x: %s\n", rc, wolfTPM2_GetRCString(rc)); diff --git a/examples/wrap/hash.c b/examples/wrap/hash.c index 66288d3f..83116629 100644 --- a/examples/wrap/hash.c +++ b/examples/wrap/hash.c @@ -75,21 +75,32 @@ int TPM2_Hash_Example(void* userCtx, int argc, char* argv[]) hashAlg = TPM_ALG_SHA256; hashAlgName = "SHA-256"; } - #ifdef WOLFSSL_SHA384 else if (XSTRCMP(argv[i], "-sha384") == 0) { + #ifdef WOLFSSL_SHA384 hashAlg = TPM_ALG_SHA384; hashAlgName = "SHA-384"; + #else + printf("SHA-384 not enabled in this build\n"); + return 0; + #endif } - #endif - #ifdef WOLFSSL_SHA512 else if (XSTRCMP(argv[i], "-sha512") == 0) { + #ifdef WOLFSSL_SHA512 hashAlg = TPM_ALG_SHA512; hashAlgName = "SHA-512"; + #else + printf("SHA-512 not enabled in this build\n"); + return 0; + #endif } - #endif else if (argv[i][0] != '-') { message = argv[i]; } + else { + printf("Unknown option: %s\n", argv[i]); + usage(); + return -1; + } } printf("TPM2 Hash Example (%s)\n", hashAlgName);