Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 89 additions & 29 deletions examples/native/native_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,53 @@ static int is_curve_or_cmd_unsupported(TPM_RC rc, int curveMayBeUnsupported)
return 0;
}

/* TPM2_EncryptDecrypt(2) is commonly shipped switched off for export-control
* reasons. A TPM that does not implement it at all answers TPM_RC_COMMAND_CODE,
* while one that implements it but leaves it disabled answers TPM_RC_DISABLED,
* which can persist even after TPM2_SetCommandSet. Both mean the same thing to
* this example: skip the test rather than fail the run. */
static int native_is_cmd_unavailable_or_disabled(TPM_RC rc)
{
if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
return 1;
}
if (rc >= 0 && (((UINT32)rc) & 0xFFFFu) == (UINT32)TPM_RC_DISABLED) {
return 1;
}
return 0;
}

/* Report whether the TPM implements a given algorithm, by asking it rather
* than assuming. TPM_CAP_ALGS returns algorithms with ID >= property, so a
* match at index 0 of a single-property query means it is implemented.
* Returns 1 when supported, 0 when it is not or the query fails, so a caller
* skips rather than proceeding on an unanswered question. */
static int native_is_alg_supported(TPM_ALG_ID alg)
{
int rc;
GetCapability_In in;
GetCapability_Out out;
TPML_ALG_PROPERTY* algs;

XMEMSET(&in, 0, sizeof(in));
XMEMSET(&out, 0, sizeof(out));
in.capability = TPM_CAP_ALGS;
in.property = alg;
in.propertyCount = 1;
rc = TPM2_GetCapability(&in, &out);
if (rc != TPM_RC_SUCCESS) {
return 0;
}
if (out.capabilityData.capability != TPM_CAP_ALGS) {
return 0;
}
algs = &out.capabilityData.data.algorithms;
if (algs->count >= 1 && algs->algProperties[0].alg == alg) {
return 1;
}
return 0;
}

/* Run the ECDH / ECDH_ZGen / EC_Ephemeral / ZGen_2Phase sequence against a
* single curve. Creates a transient ECDH key under `parentHandle`, exercises
* the two-phase key-exchange path, and validates that the returned
Expand Down Expand Up @@ -863,22 +910,28 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
TPM2_PrintBin(cmdOut.policyGetDigest.policyDigest.buffer,
cmdOut.policyGetDigest.policyDigest.size);

/* Read PCR[0] SHA1 */
pcrIndex = 0;
XMEMSET(&cmdIn.pcrRead, 0, sizeof(cmdIn.pcrRead));
TPM2_SetupPCRSel(&cmdIn.pcrRead.pcrSelectionIn, TPM_ALG_SHA1, pcrIndex);
rc = TPM2_PCR_Read(&cmdIn.pcrRead, &cmdOut.pcrRead);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PCR_Read failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
/* Read PCR[0] SHA1. Many current TPMs no longer implement SHA-1 and have
* no SHA-1 PCR bank, so ask first instead of failing on TPM_RC_HASH. */
if (!native_is_alg_supported(TPM_ALG_SHA1)) {
Comment thread
dgarske marked this conversation as resolved.
printf("TPM2_PCR_Read: SHA-1 skipped (not implemented by this TPM)\n");
}
else {
pcrIndex = 0;
XMEMSET(&cmdIn.pcrRead, 0, sizeof(cmdIn.pcrRead));
TPM2_SetupPCRSel(&cmdIn.pcrRead.pcrSelectionIn, TPM_ALG_SHA1, pcrIndex);
rc = TPM2_PCR_Read(&cmdIn.pcrRead, &cmdOut.pcrRead);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PCR_Read failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
}
printf("TPM2_PCR_Read: Index %d, Digest Sz %d, Update Counter %d\n",
pcrIndex,
(int)cmdOut.pcrRead.pcrValues.digests[0].size,
(int)cmdOut.pcrRead.pcrUpdateCounter);
TPM2_PrintBin(cmdOut.pcrRead.pcrValues.digests[0].buffer,
cmdOut.pcrRead.pcrValues.digests[0].size);
}
printf("TPM2_PCR_Read: Index %d, Digest Sz %d, Update Counter %d\n",
pcrIndex,
(int)cmdOut.pcrRead.pcrValues.digests[0].size,
(int)cmdOut.pcrRead.pcrUpdateCounter);
TPM2_PrintBin(cmdOut.pcrRead.pcrValues.digests[0].buffer,
cmdOut.pcrRead.pcrValues.digests[0].size);

#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Set Auth Session index 0 */
Expand All @@ -892,20 +945,26 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
session[0].nonceCaller.size = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST);
session[0].auth = sessionAuth;

/* Policy PCR (Get) */
pcrIndex = 0;
XMEMSET(&cmdIn.policyPCR, 0, sizeof(cmdIn.policyPCR));
cmdIn.policyPCR.policySession = sessionHandle;
cmdIn.policyPCR.pcrDigest.size = 0;
TPM2_SetupPCRSel(&cmdIn.policyPCR.pcrs, TPM_ALG_SHA1, pcrIndex);
rc = TPM2_PolicyPCR(&cmdIn.policyPCR);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PolicyPCR failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
/* Policy PCR (Get). Uses the SHA-1 PCR bank, so skip it on a TPM that
* does not implement SHA-1. */
if (!native_is_alg_supported(TPM_ALG_SHA1)) {
printf("TPM2_PolicyPCR: SHA-1 skipped (not implemented by this TPM)\n");
}
else {
printf("TPM2_PolicyPCR: Updated\n");
pcrIndex = 0;
XMEMSET(&cmdIn.policyPCR, 0, sizeof(cmdIn.policyPCR));
cmdIn.policyPCR.policySession = sessionHandle;
cmdIn.policyPCR.pcrDigest.size = 0;
TPM2_SetupPCRSel(&cmdIn.policyPCR.pcrs, TPM_ALG_SHA1, pcrIndex);
rc = TPM2_PolicyPCR(&cmdIn.policyPCR);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PolicyPCR failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
}
else {
printf("TPM2_PolicyPCR: Updated\n");
}
}
XMEMSET(&session[0], 0, sizeof(TPM2_AUTH_SESSION));
session[0].sessionHandle = TPM_RS_PW;
Expand Down Expand Up @@ -1635,7 +1694,7 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
cmdIn.encDec.decrypt = NO;
cmdIn.encDec.mode = TEST_AES_MODE;
rc = TPM2_EncryptDecrypt2(&cmdIn.encDec, &cmdOut.encDec);
if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) { /* some TPM's may not support command */
if (native_is_cmd_unavailable_or_disabled(rc)) { /* unsupported or disabled */
printf("TPM2_EncryptDecrypt2: Is not a supported feature without enabling due to export controls\n");
perform_EncryptDecrypt2 = 0;
rc = 0;
Expand All @@ -1657,8 +1716,9 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
cmdIn.encDec.decrypt = YES;
cmdIn.encDec.mode = TEST_AES_MODE;
rc = TPM2_EncryptDecrypt2(&cmdIn.encDec, &cmdOut.encDec);
if (rc == TPM_RC_COMMAND_CODE) { /* some TPM's may not support command */
if (native_is_cmd_unavailable_or_disabled(rc)) { /* unsupported or disabled */
printf("TPM2_EncryptDecrypt2: Is not a supported feature without enabling due to export controls\n");
rc = 0;
Comment on lines +1719 to +1721
}
else if (rc != TPM_RC_SUCCESS) {
printf("TPM2_EncryptDecrypt2 failed 0x%x: %s\n", rc,
Expand Down
12 changes: 12 additions & 0 deletions examples/pqc/pqc_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,17 @@ static int do_hash_mldsa(WOLFTPM2_DEV* dev, TPMI_MLDSA_PARAMETER_SET ps)

rc = wolfTPM2_VerifyDigestSignature(dev, &key, digest, (int)sizeof(digest),
sig, sigSz, NULL, 0, &validation);
if (rc == BUFFER_E) {
/* The signature is larger than this TPM's TPM_PT_INPUT_BUFFER, so it
* cannot be handed back for on-TPM verification. Signing still
* succeeded, which is the part that needs the private key; verify the
* signature on the host instead (see examples/pqc/mldsa_host_verify). */
Comment thread
dgarske marked this conversation as resolved.
printf("PASS HashML-DSA-%-3s signdigest (sig %d bytes); on-TPM "
"verify unavailable, signature exceeds input buffer\n",
mldsaName(ps), sigSz);
rc = TPM_RC_SUCCESS;
goto exit_quiet;
}
if (rc != TPM_RC_SUCCESS) goto exit;

if (validation.tag != TPM_ST_DIGEST_VERIFIED) {
Expand All @@ -510,6 +521,7 @@ static int do_hash_mldsa(WOLFTPM2_DEV* dev, TPMI_MLDSA_PARAMETER_SET ps)
printf("FAIL HashML-DSA-%-3s 0x%x: %s\n",
mldsaName(ps), rc, wolfTPM2_GetRCString(rc));
}
exit_quiet:
wolfTPM2_UnloadHandle(dev, &key.handle);
XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return rc;
Expand Down
31 changes: 21 additions & 10 deletions examples/wrap/wrap_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ int TPM2_Wrapper_Test(void* userCtx)
int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
{
int rc, i;
int isSupported = 0;
WOLFTPM2_DEV dev;
WOLFTPM2_CAPS caps;
WOLFTPM2_KEY ekKey;
Expand Down Expand Up @@ -683,19 +684,29 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
printf("ECC DH Test %s\n", rc == 0 ? "Passed" : "Failed");

/* ECC Public Key Signature Verify Test/Example */
rc = wolfTPM2_LoadEccPublicKey(&dev, &publicKey, TPM_ECC_NIST_P256,
kEccTestPubQX, sizeof(kEccTestPubQX),
kEccTestPubQY, sizeof(kEccTestPubQY));
/* The test vector below is signed over a SHA-1 digest. Many current TPMs
* no longer implement SHA-1, so ask before using it rather than aborting
* the whole test run on TPM_RC_HASH. */
rc = wolfTPM2_IsAlgSupported(&dev, TPM_ALG_SHA1, &isSupported);
if (rc != 0) goto exit;
if (!isSupported) {
printf("ECC Verify Test Skipped (TPM does not implement SHA-1)\n");
}
else {
rc = wolfTPM2_LoadEccPublicKey(&dev, &publicKey, TPM_ECC_NIST_P256,
kEccTestPubQX, sizeof(kEccTestPubQX),
kEccTestPubQY, sizeof(kEccTestPubQY));
if (rc != 0) goto exit;

rc = wolfTPM2_VerifyHashScheme(&dev, &publicKey,
kEccTestSigRS, sizeof(kEccTestSigRS),
kEccTestMsg, sizeof(kEccTestMsg), TPM_ALG_ECDSA, TPM_ALG_SHA1);
if (rc != 0) goto exit;
rc = wolfTPM2_VerifyHashScheme(&dev, &publicKey,
kEccTestSigRS, sizeof(kEccTestSigRS),
kEccTestMsg, sizeof(kEccTestMsg), TPM_ALG_ECDSA, TPM_ALG_SHA1);
if (rc != 0) goto exit;

rc = wolfTPM2_UnloadHandle(&dev, &publicKey.handle);
if (rc != 0) goto exit;
printf("ECC Verify Test Passed\n");
rc = wolfTPM2_UnloadHandle(&dev, &publicKey.handle);
if (rc != 0) goto exit;
printf("ECC Verify Test Passed\n");
}

/*------------------------------------------------------------------------*/
/* ECC KEY LOADING TESTS */
Expand Down
71 changes: 63 additions & 8 deletions src/tpm2_tis.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,22 +411,73 @@ int TPM2_TIS_Status(TPM2_CTX* ctx, byte* status)
sizeof(*status));
}

/* Budget for the TIS wait loops below.
*
* Counting iterations makes the real timeout depend on the host: how fast it
* runs the loop, and how long XTPM_WAIT() actually sleeps, which on Linux is
* anywhere from 10 to 60 us for a nominal 10 us usleep() depending on timer
* granularity and scheduling. A TPM whose RSA key generation takes above 20
* seconds then sits right on the boundary and times out intermittently on the
* same operation that succeeded a moment earlier.
*
* Where the platform offers a monotonic clock, bound the wait by TPM_TIMEOUT_MS
* of real time so the budget means the same thing on every host. Where it does
* not, keep counting iterations exactly as before - no port acquires a new
* requirement, and behaviour there is unchanged. */
typedef struct TPM2_TIS_TIMEOUT {
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
word32 start;
int haveStart;
#endif
int tries;
} TPM2_TIS_TIMEOUT;

static void TPM2_TIS_TimeoutStart(TPM2_TIS_TIMEOUT* to)
{
XMEMSET(to, 0, sizeof(*to));
to->tries = TPM_TIMEOUT_TRIES;
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
to->start = XTPM_GET_TIMEMS();
/* a zero tick means the clock could not be read; count instead */
to->haveStart = (to->start != 0) ? 1 : 0;
#endif
}

/* Returns 1 once the budget is spent, 0 while there is still time. */
static int TPM2_TIS_TimeoutExpired(TPM2_TIS_TIMEOUT* to)
{
if (to->tries > 0) {
to->tries--;
}
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
if (to->haveStart) {
/* unsigned subtraction stays correct across the word32 wrap */
return ((word32)(XTPM_GET_TIMEMS() - to->start) >= TPM_TIMEOUT_MS) ?
1 : 0;
}
#endif
return (to->tries <= 0) ? 1 : 0;
}

int TPM2_TIS_WaitForStatus(TPM2_CTX* ctx, byte status, byte status_mask)
{
int rc;
int timeout = TPM_TIMEOUT_TRIES;
int expired = 0;
TPM2_TIS_TIMEOUT to;
byte reg = 0;

TPM2_TIS_TimeoutStart(&to);
do {
rc = TPM2_TIS_Status(ctx, &reg);
if (rc == TPM_RC_SUCCESS && (reg & status) == status_mask)
break;
XTPM_WAIT();
} while (rc == TPM_RC_SUCCESS && --timeout > 0);
expired = TPM2_TIS_TimeoutExpired(&to);
} while (rc == TPM_RC_SUCCESS && !expired);
#ifdef WOLFTPM_DEBUG_TIMEOUT
printf("TIS_WaitForStatus: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
printf("TIS_WaitForStatus: Timeout %d\n", TPM_TIMEOUT_TRIES - to.tries);
#endif
if (timeout <= 0)
if (expired)
return TPM_RC_TIMEOUT;
return rc;
}
Expand All @@ -452,7 +503,10 @@ int TPM2_TIS_GetBurstCount(TPM2_CTX* ctx, word16* burstCount)
#endif

{
int timeout = TPM_TIMEOUT_TRIES;
int expired = 0;
TPM2_TIS_TIMEOUT to;

TPM2_TIS_TimeoutStart(&to);
*burstCount = 0;
do {
rc = TPM2_TIS_Read(ctx, TPM_BURST_COUNT(ctx->locality),
Expand All @@ -463,16 +517,17 @@ int TPM2_TIS_GetBurstCount(TPM2_CTX* ctx, word16* burstCount)
if (rc == TPM_RC_SUCCESS && *burstCount > 0)
break;
XTPM_WAIT();
} while (rc == TPM_RC_SUCCESS && --timeout > 0);
expired = TPM2_TIS_TimeoutExpired(&to);
} while (rc == TPM_RC_SUCCESS && !expired);

#ifdef WOLFTPM_DEBUG_TIMEOUT
printf("TIS_GetBurstCount: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
printf("TIS_GetBurstCount: Timeout %d\n", TPM_TIMEOUT_TRIES - to.tries);
#endif

if (*burstCount > MAX_SPI_FRAMESIZE)
*burstCount = MAX_SPI_FRAMESIZE;

if (timeout <= 0)
if (expired)
return TPM_RC_TIMEOUT;
}

Expand Down
Loading
Loading