Compare commits

...

16 Commits

Author SHA1 Message Date
Zackery 8b2e4271d3
Merge pull request #420 from dgarske/cmake_threadls
Fix CMake logic for `WOLFTPM_NO_ACTIVE_THREAD_LS`
2025-06-12 09:43:29 -06:00
David Garske 8ce8eaaeba Fix CMake logic for `WOLFTPM_NO_ACTIVE_THREAD_LS`. ZD 19829 2025-06-10 09:31:25 -07:00
Eric Blankenhorn 33a532f58c
Merge pull request #419 from dgarske/parsepubsz
Fix `TPM2_ParsePublic` size argument
2025-06-06 15:07:26 -05:00
David Garske 47193894e8 Cleanups for make_credential and `keygen -rsa` test case 2025-06-04 14:45:30 -07:00
David Garske d5872221ba Fix `TPM2_ParsePublic` size argument. 2025-06-02 16:33:18 -07:00
Eric Blankenhorn bd682553ac
Merge pull request #418 from dgarske/tpmsign
Fix logic for signing with input digest smaller than key size
2025-06-02 15:56:48 -05:00
David Garske a45f922c6d Fix for older TPM's that don't support ECC384/SHA384. 2025-06-02 08:11:09 -07:00
David Garske f1507c697b Minor cleanups. Fixed `test_TPM2_PCRSel` test. 2025-06-02 08:11:09 -07:00
David Garske 592210f321 Expose `TPM2_ASN_TrimZeros`. 2025-06-02 08:11:08 -07:00
David Garske 3e3038854c Improve input digest size logic for TPM2_Sign and TPM2_Verify. Added test case with interop. 2025-06-02 08:11:08 -07:00
David Garske 32332fd2bb Fix logic for signing with input digest smaller than key size. ZD 19869 2025-06-02 08:11:08 -07:00
Eric Blankenhorn 761cb4adea
Merge pull request #417 from dgarske/tpm_threadls
Improve active TPM thread mutex and possible mutex recursion
2025-05-29 11:18:22 -05:00
David Garske c364166542 Fix for missing `TPM2_ReleaseLock` in `TPM2_GetProductInfo`. 2025-05-28 16:04:51 -07:00
David Garske 7411bc115f Refactor the TPM2_GetNonce to support a non-locking version for internal use. This avoids all possible recursive mutex calls. 2025-05-27 14:42:43 -07:00
David Garske 4214ffa8a5 Improvements to CMake support for single threading, mutex locking and active thread local storage. 2025-05-27 12:36:57 -07:00
David Garske cbb7c2969b Improve gActiveTPM detection for needing thread local. 2025-05-27 12:24:57 -07:00
14 changed files with 394 additions and 119 deletions

View File

@ -79,11 +79,41 @@ check_function_exists("gettimeofday" HAVE_GETTIMEOFDAY)
# * wait state
# * small stack
# Single threaded
set(WOLFTPM_SINGLE_THREADED "no" CACHE STRING
"Enable wolfTPM single threaded (default: disabled)")
set_property(CACHE WOLFTPM_SINGLE_THREADED
PROPERTY STRINGS "yes;no")
if(WOLFTPM_SINGLE_THREADED)
list(APPEND WOLFTPM_DEFINITIONS
"-DSINGLE_THREADED")
endif()
# Mutex locking
set(WOLFTPM_NO_LOCK "no" CACHE STRING
"Enable thread mutex locking (default: enabled)")
set_property(CACHE WOLFTPM_NO_LOCK
PROPERTY STRINGS "yes;no")
if(NOT WOLFTPM_NO_LOCK)
list(APPEND WOLFTPM_DEFINITIONS
"-DWOLFTPM_NO_LOCK")
endif()
# Active TPM - Thread local storage
set(WOLFTPM_NO_ACTIVE_THREAD_LS "no" CACHE STRING
"Disable active TPM thread local storage (default: disabled)")
set_property(CACHE WOLFTPM_NO_ACTIVE_THREAD_LS
PROPERTY STRINGS "yes;no")
if(WOLFTPM_NO_ACTIVE_THREAD_LS)
list(APPEND WOLFTPM_DEFINITIONS
"-DWOLFTPM_NO_ACTIVE_THREAD_LS")
endif()
# Provisioning
set(WOLFTPM_PROVISIONING "yes" CACHE STRING
"Enable support for Provisioning Initial Device Identity (IDevID) and Attestation Identity Keys (default: enabled)")
set_property(CACHE WOLFTPM_PROVISIONING
PROPERTY STRINGS "yes;no;verbose")
PROPERTY STRINGS "yes;no")
if(WOLFTPM_PROVISIONING)
list(APPEND WOLFTPM_DEFINITIONS
"-DWOLFTPM_PROVISIONING")

View File

@ -36,6 +36,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\tpm2.c" />
<ClCompile Include="..\..\src\tpm2_asn.c" />
<ClCompile Include="..\..\src\tpm2_cryptocb.c" />
<ClCompile Include="..\..\src\tpm2_packet.c" />
<ClCompile Include="..\..\src\tpm2_param_enc.c" />

View File

@ -49,8 +49,8 @@ static void usage(void)
printf("Notes:\n");
printf("\tName digest is loaded from \"ak.name\" file\n");
printf("\tPublic key is loaded from a file containing TPM2B_PUBLIC\n");
printf("\t\"tek.pub\" for EK pub");
printf("\t\"tsrk.pub\" for SRK pub");
printf("\t\"ek.pub\" for EK pub\n");
printf("\t\"srk.pub\" for SRK pub\n");
printf("\tOutput is stored in \"cred.blob\"\n");
printf("Demo usage without parameters, uses SRK pub\n");
}

View File

@ -221,7 +221,7 @@ int TPM2_NVRAM_Read_Example(void* userCtx, int argc, char *argv[])
/* Necessary for storing the publicArea with the correct encoding */
rc = TPM2_ParsePublic(&keyBlob.pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
readSize, &pubAreaSize);
if (rc != TPM_RC_SUCCESS) {
printf("Decoding of PublicArea failed. Unable to extract correctly.\n");
goto exit;

View File

@ -378,7 +378,7 @@ run_tpm_tls_client() { # Usage: run_tpm_tls_client [ecc/rsa] [tpmargs] [tlsversi
generate_port
pushd $WOLFSSL_PATH >> $TPMPWD/run.out 2>&1
echo -e "./examples/server/server -v $3 -p $port -w -g -A ./certs/tpm-ca-$1-cert.pem"
./examples/server/server -p $port -w -g -A ./certs/tpm-ca-$1-cert.pem &> $TPMPWD/run.out &
./examples/server/server -p $port -w -g -A ./certs/tpm-ca-$1-cert.pem >> $TPMPWD/run.out 2>&1 &
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "tls server $1 $2 failed! $RESULT" && exit 1
popd >> $TPMPWD/run.out 2>&1
@ -493,17 +493,9 @@ if [ $WOLFCRYPT_ENABLE -eq 1 ]; then
fi
if [ $WOLFCRYPT_ENABLE -eq 1 ] && [ $NO_FILESYSTEM -eq 0 ]; then
./examples/keygen/keygen keyblob.bin -rsa >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "keygen rsa failed! $RESULT" && exit 1
./examples/attestation/make_credential >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "make_credential failed! $RESULT" && exit 1
./examples/attestation/activate_credential >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "activate_credential failed! $RESULT" && exit 1
rm -f keyblob.bin
# Endorsement hierarchy
# Endorsement hierarchy (assumes keyblob.bin for key)
./examples/keygen/keygen keyblob.bin -rsa -eh >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "keygen rsa endorsement failed! $RESULT" && exit 1
@ -514,10 +506,21 @@ if [ $WOLFCRYPT_ENABLE -eq 1 ] && [ $NO_FILESYSTEM -eq 0 ]; then
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "activate_credential endorsement failed! $RESULT" && exit 1
./examples/keygen/keygen keyblob.bin -rsa >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "keygen rsa failed! $RESULT" && exit 1
./examples/attestation/make_credential >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "make_credential failed! $RESULT" && exit 1
./examples/attestation/activate_credential >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "activate_credential failed! $RESULT" && exit 1
rm -f cred.blob
rm -f ek.pub
rm -f srk.pub
rm -f ak.name
# Keeping keyblob.bin for tests later
fi
# PCR Quote Tests

View File

@ -535,7 +535,7 @@ int TPM2_TLS_ServerArgs(void* userCtx, int argc, char *argv[])
rc = wolfSSL_CTX_use_certificate_file(ctx, useCert, WOLFSSL_FILETYPE_PEM);
#endif
if (rc != WOLFSSL_SUCCESS) {
#ifndef NO_FILESYSTEM
#if !defined(NO_FILESYSTEM) && !defined(WOLFTPM_MFG_IDENTITY)
printf("Error loading ECC client cert: %s\n", useCert);
#else
printf("Error loading ECC client cert\n");

View File

@ -216,7 +216,7 @@ int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key)
/* Decode the byte stream into a publicArea structure ready for use */
rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
sizeof(UINT16) + key->pub.size, &pubAreaSize);
if (rc != TPM_RC_SUCCESS) {
goto exit;
}

View File

@ -37,23 +37,26 @@
/* --- Local Variables -- */
/******************************************************************************/
#ifdef WOLFTPM_NO_ACTIVE_THREAD_LS
/* if using gHwLock and want to use a shared active TPM2_CTX between threads */
static TPM2_CTX* gActiveTPM;
#else
static THREAD_LS_T TPM2_CTX* gActiveTPM;
#endif
#ifndef WOLFTPM2_NO_WOLFCRYPT
static volatile int gWolfCryptRefCount = 0;
#endif
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(WOLFTPM_NO_LOCK) && \
!defined(SINGLE_THREADED)
/* if a mutex lock is supported, then don't use thread local on gActiveTPM */
#undef WOLFTPM_NO_ACTIVE_THREAD_LS
#define WOLFTPM_NO_ACTIVE_THREAD_LS
static wolfSSL_Mutex gHwLock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(gHwLock);
#endif
#ifdef WOLFTPM_NO_ACTIVE_THREAD_LS
/* if using gHwLock and want to use a shared active TPM2_CTX between threads */
static TPM2_CTX* gActiveTPM;
#else
static THREAD_LS_T TPM2_CTX* gActiveTPM;
#endif
#ifdef WOLFTPM_LINUX_DEV
#define INTERNAL_SEND_COMMAND TPM2_LINUX_SendCommand
#define TPM2_INTERNAL_CLEANUP(ctx)
@ -160,7 +163,7 @@ static int TPM2_CommandProcess(TPM2_CTX* ctx, TPM2_Packet* packet,
if (session->sessionHandle != TPM_RS_PW) {
/* Generate fresh nonce */
rc = TPM2_GetNonce(session->nonceCaller.buffer,
rc = TPM2_GetNonceNoLock(session->nonceCaller.buffer,
session->nonceCaller.size);
if (rc != TPM_RC_SUCCESS) {
return rc;
@ -5464,6 +5467,7 @@ TPM_RC TPM2_GetProductInfo(uint8_t* info, uint16_t size)
size = packet.size - 26;
XMEMCPY(info, &packet.buf[25], size);
}
TPM2_ReleaseLock(ctx);
}
return rc;
}
@ -5686,9 +5690,7 @@ int TPM2_GetHashType(TPMI_ALG_HASH hashAlg)
return 0;
}
/* Can optionally define WOLFTPM2_USE_HW_RNG to force using TPM hardware for
* RNG source */
int TPM2_GetNonce(byte* nonceBuf, int nonceSz)
int TPM2_GetNonceNoLock(byte* nonceBuf, int nonceSz)
{
int rc;
TPM2_CTX* ctx = TPM2_GetActiveCtx();
@ -5717,8 +5719,6 @@ int TPM2_GetNonce(byte* nonceBuf, int nonceSz)
#else
/* Call GetRandom directly, so a custom packet buffer can be used.
* This won't conflict when being called from TPM2_CommandProcess. */
rc = TPM2_AcquireLock(ctx);
if (rc == TPM_RC_SUCCESS) {
while (randSz < nonceSz) {
UINT16 inSz = nonceSz - randSz, outSz = 0;
if (inSz > MAX_RNG_REQ_SIZE) {
@ -5748,9 +5748,25 @@ int TPM2_GetNonce(byte* nonceBuf, int nonceSz)
TPM2_Packet_ParseBytes(&packet, &nonceBuf[randSz], outSz);
randSz += outSz;
}
#endif
return rc;
}
int TPM2_GetNonce(byte* nonceBuf, int nonceSz)
{
int rc;
TPM2_CTX* ctx = TPM2_GetActiveCtx();
if (ctx == NULL) {
return BAD_FUNC_ARG;
}
rc = TPM2_AcquireLock(ctx);
if (rc == TPM_RC_SUCCESS) {
rc = TPM2_GetNonceNoLock(nonceBuf, nonceSz);
TPM2_ReleaseLock(ctx);
}
#endif
return rc;
}
@ -6449,13 +6465,6 @@ int TPM2_ParsePublic(TPM2B_PUBLIC* pub, byte* buf, word32 size, int* sizeUsed)
if (buf == NULL || pub == NULL || sizeUsed == NULL)
return BAD_FUNC_ARG;
if (size < sizeof(TPM2B_PUBLIC)) {
#ifdef DEBUG_WOLFTPM
printf("Insufficient buffer size for TPM2B_PUBLIC operations\n");
#endif
return TPM_RC_FAILURE;
}
/* Prepare temporary buffer */
packet.buf = buf;
packet.pos = 0;

View File

@ -27,6 +27,18 @@
#ifndef WOLFTPM2_NO_ASN
/* Helper to trim leading zeros when not required */
byte* TPM2_ASN_TrimZeros(byte* in, word32* len)
{
word32 idx = 0;
while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) {
idx++;
in++;
}
*len -= idx;
return in;
}
int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
word32 maxIdx, int check)
{

View File

@ -24,24 +24,10 @@
#endif
#include <wolftpm/tpm2_wrap.h>
#include <wolftpm/tpm2_asn.h>
#if !defined(WOLFTPM2_NO_WRAPPER)
#if defined(HAVE_ECC) && (defined(WOLFTPM_CRYPTOCB) || \
(defined(HAVE_PK_CALLBACKS) && !defined(WOLFCRYPT_ONLY)))
/* Helper to trim leading zeros when not required */
static byte* wolfTPM2_ASNTrimZeros(byte* in, word32* len)
{
word32 idx = 0;
while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) {
idx++;
in++;
}
*len -= idx;
return in;
}
#endif
#ifdef WOLFTPM_CRYPTOCB
/* Internal structure for tracking hash state */
@ -272,8 +258,8 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
rLen = sLen = rsLen / 2;
r = &sigRS[0];
s = &sigRS[rLen];
r = wolfTPM2_ASNTrimZeros(r, &rLen);
s = wolfTPM2_ASNTrimZeros(s, &sLen);
r = TPM2_ASN_TrimZeros(r, &rLen);
s = TPM2_ASN_TrimZeros(s, &sLen);
/* Encode ECDSA Header */
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen,
@ -1134,8 +1120,8 @@ int wolfTPM2_PK_EccSign(WOLFSSL* ssl,
rLen = sLen = rsLen / 2;
r = &sigRS[0];
s = &sigRS[rLen];
r = wolfTPM2_ASNTrimZeros(r, &rLen);
s = wolfTPM2_ASNTrimZeros(s, &sLen);
r = TPM2_ASN_TrimZeros(r, &rLen);
s = TPM2_ASN_TrimZeros(s, &sLen);
/* Encode ECDSA Header */
ret = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outSz);

View File

@ -481,7 +481,7 @@ int wolfTPM2_SetKeyBlobFromBuffer(WOLFTPM2_KEYBLOB* key, byte *buffer,
/* Decode the byte stream into a publicArea structure ready for use */
rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
(word32)(sizeof(UINT16) + key->pub.size), &pubAreaSize);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
@ -1592,7 +1592,7 @@ int wolfTPM2_StartSession(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
authSesIn.symmetric.algorithm = TPM_ALG_NULL;
}
authSesIn.nonceCaller.size = hashDigestSz;
rc = TPM2_GetNonce(authSesIn.nonceCaller.buffer,
rc = TPM2_GetNonceNoLock(authSesIn.nonceCaller.buffer,
authSesIn.nonceCaller.size);
if (rc < 0) {
#ifdef DEBUG_WOLFTPM
@ -1604,7 +1604,7 @@ int wolfTPM2_StartSession(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
if (authSesIn.tpmKey != TPM_RH_NULL) {
/* Generate random salt */
session->salt.size = hashDigestSz;
rc = TPM2_GetNonce(session->salt.buffer, session->salt.size);
rc = TPM2_GetNonceNoLock(session->salt.buffer, session->salt.size);
if (rc != 0) {
return rc;
}
@ -2481,6 +2481,7 @@ int wolfTPM2_ImportRsaPrivateKeySeed(WOLFTPM2_DEV* dev,
TPMI_ALG_RSA_SCHEME scheme, TPMI_ALG_HASH hashAlg, TPMA_OBJECT attributes,
byte* seed, word32 seedSz)
{
int rc = 0;
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
word32 digestSz;
@ -2544,11 +2545,13 @@ int wolfTPM2_ImportRsaPrivateKeySeed(WOLFTPM2_DEV* dev,
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
if (rc == 0) {
rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
return rc;
}
int wolfTPM2_ImportRsaPrivateKey(WOLFTPM2_DEV* dev,
const WOLFTPM2_KEY* parentKey, WOLFTPM2_KEYBLOB* keyBlob, const byte* rsaPub,
@ -2633,6 +2636,7 @@ int wolfTPM2_ImportEccPrivateKeySeed(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* pare
const byte* eccPriv, word32 eccPrivSz,
TPMA_OBJECT attributes, byte* seed, word32 seedSz)
{
int rc = 0;
TPM2B_PUBLIC pub;
TPM2B_SENSITIVE sens;
word32 digestSz;
@ -2696,11 +2700,14 @@ int wolfTPM2_ImportEccPrivateKeySeed(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* pare
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
return wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
if (rc == 0) {
rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, &pub, &sens);
}
return rc;
}
int wolfTPM2_ImportEccPrivateKey(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* parentKey,
@ -3234,14 +3241,15 @@ int wolfTPM2_ImportPrivateKeyBuffer(WOLFTPM2_DEV* dev,
else {
/* assign random seed */
sens.sensitiveArea.seedValue.size = digestSz;
TPM2_GetNonce(sens.sensitiveArea.seedValue.buffer,
rc = TPM2_GetNonceNoLock(sens.sensitiveArea.seedValue.buffer,
sens.sensitiveArea.seedValue.size);
}
if (rc == 0) {
/* Import Private Key */
rc = wolfTPM2_ImportPrivateKey(dev, parentKey, keyBlob, pub, &sens);
}
}
#ifdef WOLFTPM2_PEM_DECODE
if (derBuf != (byte*)input) {
@ -3764,10 +3772,24 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
/* set session auth for key */
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
/* verify input cannot exceed buffer */
if (digestSz > (int)sizeof(signIn.digest.buffer))
digestSz = (int)sizeof(signIn.digest.buffer);
XMEMSET(&signIn, 0, sizeof(signIn));
signIn.keyHandle = key->handle.hndl;
signIn.digest.size = digestSz;
XMEMCPY(signIn.digest.buffer, digest, signIn.digest.size);
signIn.digest.size = TPM2_GetHashDigestSize(hashAlg);
if (signIn.digest.size <= 0) {
return BAD_FUNC_ARG;
}
/* if digest provided is smaller than key size then zero pad leading */
if (digestSz < signIn.digest.size) {
XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz], digest,
digestSz);
}
else {
XMEMCPY(signIn.digest.buffer, digest, digestSz);
}
signIn.inScheme.scheme = sigAlg;
signIn.inScheme.details.any.hashAlg = hashAlg;
signIn.validation.tag = TPM_ST_HASHCHECK;
@ -3910,8 +3932,18 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
XMEMSET(&verifySigIn, 0, sizeof(verifySigIn));
verifySigIn.keyHandle = key->handle.hndl;
verifySigIn.digest.size = digestSz;
verifySigIn.digest.size = TPM2_GetHashDigestSize(hashAlg);
if (verifySigIn.digest.size <= 0) {
return BAD_FUNC_ARG;
}
/* if digest provided is smaller than key size then zero pad leading */
if (digestSz < verifySigIn.digest.size) {
XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size - digestSz],
digest, digestSz);
}
else {
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
}
verifySigIn.signature.sigAlg = sigAlg;
verifySigIn.signature.signature.any.hashAlg = hashAlg;
if (key->pub.publicArea.type == TPM_ALG_ECC) {
@ -5776,7 +5808,7 @@ int wolfTPM2_ChangeHierarchyAuth(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session,
}
}
if (rc == 0) {
rc = TPM2_GetNonce(in.newAuth.buffer, in.newAuth.size);
rc = TPM2_GetNonceNoLock(in.newAuth.buffer, in.newAuth.size);
}
if (rc == 0) {
rc = TPM2_HierarchyChangeAuth(&in);

View File

@ -28,6 +28,7 @@
#include <wolftpm/tpm2.h>
#include <wolftpm/tpm2_wrap.h>
#include <wolftpm/tpm2_param_enc.h>
#include <wolftpm/tpm2_asn.h>
#include <hal/tpm_io.h>
#include <examples/tpm_test.h>
@ -100,7 +101,8 @@ static void test_wolfTPM2_Init(void)
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)
#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
@ -275,11 +277,12 @@ static void test_TPM2_PCRSel(void)
/* Test bad case - invalid PCR */
XMEMSET(&pcr, 0, sizeof(pcr));
pcrArray[0] = PCR_SELECT_MAX+1;
pcrArray[0] = PCR_LAST+1;
TPM2_SetupPCRSelArray(&pcr, TPM_ALG_SHA256, pcrArray, 1);
if (pcr.count != 0) {
rc = BAD_FUNC_ARG;
}
AssertIntEQ(rc, 0);
/* Test bad case - too many hash algorithms */
XMEMSET(&pcr, 0, sizeof(pcr));
@ -294,6 +297,7 @@ static void test_TPM2_PCRSel(void)
if (pcr.count != HASH_COUNT) {
rc = BAD_FUNC_ARG;
}
AssertIntEQ(rc, 0);
printf("Test TPM Wrapper:\tPCR Select Array:\t%s\n",
rc == 0 ? "Passed" : "Failed");
@ -345,7 +349,8 @@ static void test_TPM2_KDFa(void)
0xd7, 0x04, 0xb6, 0x9a, 0x90, 0x2e, 0x9a, 0xde, 0x84, 0xc4};
#endif
rc = TPM2_KDFa(TPM_ALG_SHA256, &keyIn, label, &contextU, &contextV, key, keyIn.size);
rc = TPM2_KDFa(TPM_ALG_SHA256, &keyIn, label, &contextU, &contextV, key,
keyIn.size);
#ifdef WOLFTPM2_NO_WOLFCRYPT
AssertIntEQ(NOT_COMPILED_IN, rc);
#else
@ -396,6 +401,172 @@ static void test_wolfTPM2_CSR(void)
#endif
}
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
!defined(WOLFTPM2_NO_ASN)
static void test_wolfTPM2_EccSignVerifyDig(WOLFTPM2_DEV* dev,
WOLFTPM2_KEY* storageKey, const byte* digest, int digestSz,
TPM_ECC_CURVE curve, TPMI_ALG_HASH hashAlg)
{
int rc;
int verifyRes = 0;
WOLFTPM2_KEY eccKey;
TPMT_PUBLIC publicTemplate;
byte sigRs[MAX_ECC_BYTES*2];
word32 sigRsSz = (word32)sizeof(sigRs);
byte sig[ECC_MAX_SIG_SIZE];
word32 sigSz;
byte *r, *s;
word32 rLen, sLen;
ecc_key wolfKey;
int curveSize = TPM2_GetCurveSize(curve);
/* -- Use TPM key to sign and verify with wolfCrypt -- */
/* Create ECC key for signing */
rc = wolfTPM2_GetKeyTemplate_ECC_ex(&publicTemplate, hashAlg,
(TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
TPMA_OBJECT_sign | TPMA_OBJECT_noDA),
curve, TPM_ALG_ECDSA, hashAlg);
AssertIntEQ(rc, 0);
rc = wolfTPM2_CreateAndLoadKey(dev, &eccKey, &storageKey->handle,
&publicTemplate, (byte*)gKeyAuth, sizeof(gKeyAuth)-1);
if ((rc & TPM_RC_HASH) == TPM_RC_HASH) {
printf("Hash type not supported... Skipping\n");
return;
}
AssertIntEQ(rc, 0);
/* Sign with TPM */
rc = wolfTPM2_SignHashScheme(dev, &eccKey, digest, digestSz,
sigRs, (int*)&sigRsSz, TPM_ALG_ECDSA, hashAlg);
AssertIntEQ(rc, 0);
/* Make sure leading zero's not required are trimmed */
rLen = sLen = sigRsSz / 2;
r = &sigRs[0];
s = &sigRs[rLen];
r = TPM2_ASN_TrimZeros(r, &rLen);
s = TPM2_ASN_TrimZeros(s, &sLen);
/* Encode ECDSA Header */
sigSz = (word32)sizeof(sig);
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, sig, &sigSz);
AssertIntEQ(rc, 0);
/* Initialize wolfCrypt ECC key */
rc = wc_ecc_init(&wolfKey);
AssertIntEQ(rc, 0);
/* Convert TPM key to wolfCrypt key for verification */
rc = wolfTPM2_EccKey_TpmToWolf(dev, &eccKey, &wolfKey);
AssertIntEQ(rc, 0);
/* Verify TPM signature with wolfCrypt */
rc = wc_ecc_verify_hash(sig, sigSz, digest, digestSz, &verifyRes, &wolfKey);
AssertIntEQ(rc, 0);
AssertIntEQ(verifyRes, 1); /* 1 indicates successful verification */
/* Cleanup first wolfCrypt key */
wc_ecc_free(&wolfKey);
wolfTPM2_UnloadHandle(dev, &eccKey.handle);
/* -- Use wolfCrypt key to sign and verify with TPM -- */
/* Initialize new wolfCrypt ECC key */
rc = wc_ecc_init(&wolfKey);
AssertIntEQ(rc, 0);
/* Generate new ECC key with wolfCrypt */
rc = wc_ecc_make_key(wolfTPM2_GetRng(dev), curveSize, &wolfKey);
AssertIntEQ(rc, 0);
/* Sign with wolfCrypt */
sigSz = (word32)sizeof(sig);
rc = wc_ecc_sign_hash(digest, digestSz, sig, &sigSz, wolfTPM2_GetRng(dev),
&wolfKey);
AssertIntEQ(rc, 0);
/* Decode ECDSA Header */
r = sigRs;
s = &sigRs[MAX_ECC_BYTES];
rLen = sLen = MAX_ECC_BYTES;
rc = wc_ecc_sig_to_rs(sig,
sigSz, r, &rLen, s, &sLen);
AssertIntEQ(rc, 0);
/* Convert wolfCrypt key to TPM key for verification */
rc = wolfTPM2_EccKey_WolfToTpm(dev, &wolfKey, &eccKey);
AssertIntEQ(rc, 0);
/* combine R and S at key size (zero pad leading) */
XMEMCPY(&sigRs[curveSize-rLen], r, rLen);
XMEMSET(&sigRs[0], 0, curveSize-rLen);
XMEMCPY(&sigRs[curveSize + (curveSize-sLen)], s, sLen);
XMEMSET(&sigRs[curveSize], 0, curveSize-sLen);
/* Verify wolfCrypt signature with TPM */
rc = wolfTPM2_VerifyHashScheme(dev, &eccKey, sigRs, curveSize*2,
digest, digestSz, TPM_ALG_ECDSA, hashAlg);
AssertIntEQ(rc, 0);
/* Cleanup */
wc_ecc_free(&wolfKey);
wolfTPM2_UnloadHandle(dev, &eccKey.handle);
printf("Test TPM Wrapper:\t"
"Sign/Verify (DigSz=%d, CurveSz=%d, Hash=%s):"
"\t%s\n",
digestSz, TPM2_GetCurveSize(curve), TPM2_GetAlgName(hashAlg),
rc == 0 ? "Passed" : "Failed");
}
/* Test with smaller, same and larger digest sizes using different ECC curves.
* Interop sign and verify with wolfCrypt and TPM */
static void test_wolfTPM2_EccSignVerify(void)
{
int rc, i;
byte digest[TPM_MAX_DIGEST_SIZE];
WOLFTPM2_DEV dev;
WOLFTPM2_KEY storageKey;
/* Initialize TPM */
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
AssertIntEQ(rc, 0);
/* Create storage key */
rc = wolfTPM2_CreateSRK(&dev, &storageKey, TPM_ALG_ECC,
(byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1);
AssertIntEQ(rc, 0);
for (i = 0; i < (int)sizeof(digest); i++) {
digest[i] = (byte)i;
}
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 20,
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 32,
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 48,
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 64,
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 20,
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 32,
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 48,
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 64,
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
#endif
wolfTPM2_UnloadHandle(&dev, &storageKey.handle);
wolfTPM2_Cleanup(&dev);
}
#endif
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFTPM2_PEM_DECODE) && \
!defined(NO_RSA)
static WOLFTPM2_KEY authKey; /* also used for test_wolfTPM2_PCRPolicy */
@ -479,7 +650,8 @@ static void test_wolfTPM2_PCRPolicy(void)
digest, &digestSz, NULL, 0);
AssertIntEQ(rc, 0);
AssertIntEQ(XMEMCMP(digest, expectedPolicyAuth, sizeof(expectedPolicyAuth)), 0);
AssertIntEQ(XMEMCMP(digest, expectedPolicyAuth, sizeof(expectedPolicyAuth)),
0);
rc = wolfTPM2_ResetPCR(&dev, pcrIndex);
AssertIntEQ(rc, 0);
@ -679,6 +851,10 @@ int unit_tests(int argc, char *argv[])
#endif
test_wolfTPM2_KeyBlob(TPM_ALG_RSA);
test_wolfTPM2_KeyBlob(TPM_ALG_ECC);
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
!defined(WOLFTPM2_NO_ASN)
test_wolfTPM2_EccSignVerify();
#endif
test_wolfTPM2_Cleanup();
test_wolfTPM2_thread_local_storage();
#endif /* !WOLFTPM2_NO_WRAPPER */

View File

@ -3434,7 +3434,9 @@ WOLFTPM_API TPMI_ALG_HASH TPM2_GetTpmHashType(int hashType);
/*!
\ingroup TPM2_Proprietary
\brief Generate a fresh nonce of random numbers
\note Can use the TPM random number generator if WOLFTPM2_USE_HW_RNG is defined
\note Can use the TPM random number generator if WOLFTPM2_USE_HW_RNG is defined.
To force use of the TPM's RNG use WOLFTPM2_USE_HW_RNG. Please make sure you
have parameter encryption enabled to protect the RNG data over the bus.
\return TPM_RC_SUCCESS: successful
\return TPM_RC_FAILURE: generic failure (TPM IO issue or wolfcrypt configuration)
@ -3456,6 +3458,9 @@ WOLFTPM_API TPMI_ALG_HASH TPM2_GetTpmHashType(int hashType);
*/
WOLFTPM_API int TPM2_GetNonce(byte* nonceBuf, int nonceSz);
/* Internal API for getting nonce without taking lock */
WOLFTPM_LOCAL int TPM2_GetNonceNoLock(byte* nonceBuf, int nonceSz);
/*!
\ingroup TPM2_Proprietary
\brief Helper function to prepare a correct PCR selection

View File

@ -80,8 +80,9 @@ typedef struct DecodedX509 {
\param maxIdx Maximum allowed index in buffer
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx, int* len,
word32 maxIdx);
WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx,
int* len, word32 maxIdx);
/*!
\ingroup ASN
\brief Decodes ASN.1 length with optional length checking
@ -92,8 +93,9 @@ WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx, int*
\param check Flag to enable length validation
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
word32 maxIdx, int check);
WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx,
int* len, word32 maxIdx, int check);
/*!
\ingroup ASN
\brief Decodes ASN.1 tag and validates length
@ -104,15 +106,19 @@ WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, in
\param tag Expected ASN.1 tag value
\return 0 on success, TPM_RC_INSUFFICIENT on buffer error, TPM_RC_VALUE on tag mismatch
*/
WOLFTPM_API int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz, int* inOutIdx, int* tag_len, uint8_t tag);
WOLFTPM_API int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz,
int* inOutIdx, int* tag_len, uint8_t tag);
/*!
\ingroup ASN
\brief Decodes RSA signature from ASN.1 format
\param pInput Pointer to buffer containing ASN.1 encoded RSA signature
\param inputSz Size of input buffer
\return Size of decoded signature on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
\return Size of decoded signature on success, TPM_RC_VALUE on invalid input,
TPM_RC_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz);
/*!
\brief Decodes an X.509 certificate
\param input Buffer containing ASN.1 encoded X.509 certificate
@ -120,25 +126,40 @@ WOLFTPM_API int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz);
\param x509 Structure to store decoded certificate data
\return 0 on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz, DecodedX509* x509);
WOLFTPM_API int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
DecodedX509* x509);
/*!
\ingroup ASN
\brief Decodes RSA public key from ASN.1 format into TPM2B_PUBLIC structure
\param input Buffer containing ASN.1 encoded RSA public key
\param inputSz Size of input buffer
\param pub TPM2B_PUBLIC structure to store decoded key
\return 0 on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
\return 0 on success, TPM_RC_VALUE on invalid input,
TPM_RC_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz, TPM2B_PUBLIC* pub);
WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz,
TPM2B_PUBLIC* pub);
/*!
\ingroup ASN
\brief Removes PKCS#1 v1.5 padding from RSA signature
\param pSig Pointer to buffer containing padded signature, updated to point to unpadded data
\param pSig Pointer to buffer containing padded signature, updated to point
to unpadded data
\param sigSz Size of signature buffer, updated with unpadded size
\return 0 on success, TPM_RC_VALUE on invalid padding
*/
WOLFTPM_API int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz);
/*!
\ingroup ASN
\brief Removes leading zero bytes from a buffer
\param in Pointer to input buffer containing data to trim
\param len Pointer to length of input buffer, updated with new length after trimming
\return Pointer to the trimmed buffer (may be same as input if no trimming needed)
*/
WOLFTPM_API byte* TPM2_ASN_TrimZeros(byte* in, word32* len);
#ifdef __cplusplus
} /* extern "C" */
#endif