pull/607/merge
David Garske 2026-09-17 07:11:17 -07:00 committed by GitHub
commit a755c8254f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 644 additions and 115 deletions

View File

@ -339,6 +339,7 @@ int TPM2_Native_Test(void* userCtx)
int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
{
int rc;
int isAllocated = 0;
TPM2_CTX tpm2Ctx;
union {
@ -863,22 +864,34 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
TPM2_PrintBin(cmdOut.policyGetDigest.policyDigest.buffer,
cmdOut.policyGetDigest.policyDigest.size);
/* Read PCR[0] SHA1 */
/* Many current TPMs allocate no SHA-1 bank; ask before selecting it. A
* query failure is reported, not silently treated as "no bank". */
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);
rc = TPM2_IsPcrBankAllocated(TPM_ALG_SHA1, pcrIndex, &isAllocated);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PCR_Read failed 0x%x: %s\n", rc,
printf("TPM2_IsPcrBankAllocated 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);
if (!isAllocated) {
printf("TPM2_PCR_Read: SHA-1 skipped (no SHA-1 PCR bank allocated)\n");
}
else {
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);
}
#ifndef WOLFTPM2_NO_WOLFCRYPT
/* Set Auth Session index 0 */
@ -892,20 +905,31 @@ 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) */
/* Policy PCR (Get). Selects the SHA-1 bank, so skip when unallocated. */
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);
rc = TPM2_IsPcrBankAllocated(TPM_ALG_SHA1, pcrIndex, &isAllocated);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_PolicyPCR failed 0x%x: %s\n", rc,
printf("TPM2_IsPcrBankAllocated failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
}
if (!isAllocated) {
printf("TPM2_PolicyPCR: SHA-1 skipped (no SHA-1 PCR bank allocated)\n");
}
else {
printf("TPM2_PolicyPCR: Updated\n");
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;
@ -1635,7 +1659,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 (WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) {
printf("TPM2_EncryptDecrypt2: Is not a supported feature without enabling due to export controls\n");
perform_EncryptDecrypt2 = 0;
rc = 0;
@ -1657,7 +1681,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 (WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) {
/* Leave rc set: the check below inspects it to tell a real
* result from a skip, and cmdOut holds stale output. */
printf("TPM2_EncryptDecrypt2: Is not a supported feature without enabling due to export controls\n");
}
else if (rc != TPM_RC_SUCCESS) {
@ -1673,7 +1699,7 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
cmdOut.encDec.outData.size) == 0) {
printf("Encrypt/Decrypt test success\n");
}
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) {
printf("Encrypt/Decrypt test result allowed as pass since hardware doesn't support.\n");
rc = TPM_RC_SUCCESS;
}

View File

@ -430,6 +430,15 @@ static int do_mldsa(WOLFTPM2_DEV* dev, TPMI_MLDSA_PARAMETER_SET ps)
if (rc != TPM_RC_SUCCESS) goto exit;
rc = wolfTPM2_VerifySequenceComplete(dev, seq, &key, NULL, 0,
sig, sigSz, &validation);
if (rc == BUFFER_E) {
/* Same oversize case do_hash_mldsa() reports: signing worked but the
* TPM cannot take the signature back, so skip rather than fail. */
printf("SKIP ML-DSA-%-3s signed %d bytes, not verified: "
"signature exceeds this TPM's input buffer\n",
mldsaName(ps), sigSz);
rc = TPM_RC_SUCCESS;
goto exit_quiet;
}
if (rc != TPM_RC_SUCCESS) goto exit;
seq = 0; /* Complete consumed the sequence object */
@ -448,6 +457,9 @@ exit:
printf("FAIL ML-DSA-%-3s 0x%x: %s\n",
mldsaName(ps), rc, wolfTPM2_GetRCString(rc));
}
exit_quiet:
/* The size guard runs before the sequence is consumed, so seq is still
* live on BUFFER_E and must be flushed here like any other exit. */
if (seq != 0) {
flushCtx.flushHandle = seq;
(void)TPM2_FlushContext(&flushCtx);
@ -493,6 +505,16 @@ 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) {
/* Too large for this TPM to accept back for on-TPM verification.
* Signing worked but nothing checked it, so skip, not pass. Only
* BUFFER_E means oversize; a query error still reports FAIL. */
printf("SKIP HashML-DSA-%-3s signed %d bytes, not verified: "
"signature exceeds this TPM's 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) {
@ -510,6 +532,7 @@ exit:
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;

View File

@ -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;
@ -683,19 +684,27 @@ 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));
/* Vector below uses a SHA-1 digest, which many current TPMs lack. */
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 */
@ -973,7 +982,7 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
XMEMCPY(aesIv, TEST_AES_IV, (word32)sizeof(TEST_AES_IV));
rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, message.buffer, cipher.buffer,
message.size, aesIv, (word32)sizeof(aesIv), WOLFTPM2_ENCRYPT);
if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) goto exit;
if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) goto exit;
XMEMSET(plain.buffer, 0, sizeof(plain.buffer));
plain.size = message.size;
@ -990,7 +999,7 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
XMEMCMP(cipher.buffer, TEST_AES_VERIFY, cipher.size) == 0) {
printf("Encrypt/Decrypt (known key) test success\n");
}
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) {
printf("Encrypt/Decrypt: Is not a supported feature due to export controls\n");
}
else {
@ -1020,7 +1029,7 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
XMEMSET(aesIv, 0, sizeof(aesIv));
rc = wolfTPM2_EncryptDecrypt(&dev, &aesKey, message.buffer, cipher.buffer,
message.size, aesIv, (word32)sizeof(aesIv), WOLFTPM2_ENCRYPT);
if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) goto exit;
if (rc != 0 && !WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) goto exit;
XMEMSET(plain.buffer, 0, sizeof(plain.buffer));
plain.size = message.size;
@ -1035,7 +1044,7 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
XMEMCMP(message.buffer, plain.buffer, message.size) == 0) {
printf("Encrypt/Decrypt test success\n");
}
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
else if (WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc)) {
printf("Encrypt/Decrypt: Is not a supported feature due to export controls\n");
}
else {

View File

@ -7919,6 +7919,88 @@ void TPM2_PrintPublicArea(const TPM2B_PUBLIC* pub)
}
#endif /* DEBUG_WOLFTPM */
/* TPM_CAP_ALGS returns algorithms with ID >= property, so a match at index 0
* means implemented. Fails closed: *isSupported is 0 on any error. */
int TPM2_IsAlgSupported(TPM_ALG_ID alg, int* isSupported)
{
int rc;
GetCapability_In in;
GetCapability_Out out;
TPML_ALG_PROPERTY* algs;
if (isSupported == NULL) {
return BAD_FUNC_ARG;
}
*isSupported = 0;
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 rc; /* query failure, distinct from "not supported" */
}
/* union - confirm the capability asked for */
if (out.capabilityData.capability != TPM_CAP_ALGS) {
return TPM_RC_VALUE;
}
algs = &out.capabilityData.data.algorithms;
if (algs->count >= 1 && algs->algProperties[0].alg == alg) {
*isSupported = 1;
}
return TPM_RC_SUCCESS;
}
/* Implementing a hash and allocating a bank for it are separate: a TPM may
* offer SHA-1 while allocating no SHA-1 bank, and a selection naming an
* unallocated bank is rejected. Ask before TPM2_SetupPCRSel(). Fails closed. */
int TPM2_IsPcrBankAllocated(TPM_ALG_ID hashAlg, int pcrIndex, int* isAllocated)
{
int rc;
word32 i;
GetCapability_In in;
GetCapability_Out out;
TPML_PCR_SELECTION* banks;
if (isAllocated == NULL) {
return BAD_FUNC_ARG;
}
*isAllocated = 0;
if (pcrIndex < 0) {
return BAD_FUNC_ARG;
}
XMEMSET(&in, 0, sizeof(in));
XMEMSET(&out, 0, sizeof(out));
in.capability = TPM_CAP_PCRS;
in.property = 0;
in.propertyCount = HASH_COUNT; /* all assigned banks */
rc = TPM2_GetCapability(&in, &out);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (out.capabilityData.capability != TPM_CAP_PCRS) {
return TPM_RC_VALUE;
}
banks = &out.capabilityData.data.assignedPCR;
for (i = 0; i < banks->count; i++) {
if (banks->pcrSelections[i].hash != hashAlg) {
continue;
}
if ((pcrIndex / 8) < (int)banks->pcrSelections[i].sizeofSelect &&
(banks->pcrSelections[i].pcrSelect[pcrIndex / 8] &
(1 << (pcrIndex % 8))) != 0) {
*isAllocated = 1;
break;
}
}
return TPM_RC_SUCCESS;
}
/******************************************************************************/
/* --- END Helpful API's -- */
/******************************************************************************/

View File

@ -50,7 +50,7 @@ int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
*len = 0; /* default length */
if ((idx + 1) > maxIdx) {
return TPM_RC_INSUFFICIENT;
return TPM_RC_ASN_INSUFFICIENT;
}
b = input[idx++];
@ -58,7 +58,7 @@ int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
word32 bytes = b & 0x7F;
/* DER does not allow BER indefinite-length (0x80 => bytes == 0) */
if (bytes == 0 || bytes > 3 || (idx + bytes) > maxIdx) {
return TPM_RC_INSUFFICIENT;
return TPM_RC_ASN_INSUFFICIENT;
}
while (bytes--) {
b = input[idx++];
@ -69,7 +69,7 @@ int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
length = b;
if (check && (idx + length) > maxIdx) {
return TPM_RC_INSUFFICIENT;
return TPM_RC_ASN_INSUFFICIENT;
}
*inOutIdx = idx;
@ -93,7 +93,7 @@ int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx, int* len,
\param inOutIdx Current position in buffer, updated to new position
\param len Decoded length value
\param maxIdx Maximum allowed index in buffer
\return Length on success, TPM_RC_VALUE on tag mismatch, TPM_RC_INSUFFICIENT on buffer error
\return Length on success, TPM_RC_ASN_VALUE on tag mismatch, TPM_RC_ASN_INSUFFICIENT on buffer error
*/
static int TPM2_ASN_GetHeader(const uint8_t* input, byte tag, word32* inOutIdx, int* len,
word32 maxIdx)
@ -103,14 +103,14 @@ static int TPM2_ASN_GetHeader(const uint8_t* input, byte tag, word32* inOutIdx,
int length;
if ((idx + 1) > maxIdx)
return TPM_RC_INSUFFICIENT;
return TPM_RC_ASN_INSUFFICIENT;
b = input[idx++];
if (b != tag)
return TPM_RC_VALUE;
return TPM_RC_ASN_VALUE;
if (TPM2_ASN_GetLength(input, &idx, &length, maxIdx) < 0)
return TPM_RC_VALUE;
return TPM_RC_ASN_VALUE;
*len = length;
*inOutIdx = idx;
@ -164,7 +164,7 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
byte sigParamTag = 0;
if (input == NULL || x509 == NULL) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
/* Decode outer SEQUENCE */
@ -193,14 +193,14 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
if (rc >= 0) {
if (len <= 0 || idx >= (word32)inputSz) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
}
if (rc >= 0) {
/* check version tag is INTEGER */
if (input[idx] != TPM2_ASN_INTEGER) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
}
@ -282,7 +282,7 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
if (outerSigAlgSz != tbsSigAlgSz ||
XMEMCMP(input + outerSigAlgBegin,
input + tbsSigAlgBegin, outerSigAlgSz) != 0) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
}
}
@ -299,13 +299,13 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
if (sigParamTag != TPM2_ASN_TAG_NULL &&
sigParamTag !=
(TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED)) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
else {
rc = TPM2_ASN_GetHeader(input, sigParamTag, &idx, &len,
sigAlgEnd);
if (rc >= 0 && sigParamTag == TPM2_ASN_TAG_NULL && len != 0) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
if (rc >= 0) {
idx += len;
@ -313,7 +313,7 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
}
}
if (rc >= 0 && idx != sigAlgEnd) {
rc = TPM_RC_VALUE;
rc = TPM_RC_ASN_VALUE;
}
}

View File

@ -417,22 +417,115 @@ int TPM2_TIS_Status(TPM2_CTX* ctx, byte* status)
sizeof(*status));
}
/* Budget for the wait loops below. An iteration count makes the real timeout
* depend on host speed, so a >20 s RSA key generation times out intermittently.
* Use TPM_TIMEOUT_MS of real time where a monotonic clock exists; elsewhere
* keep counting exactly as before so no port gains a requirement. */
typedef struct TPM2_TIS_TIMEOUT {
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
word32 start;
int haveStart;
#endif
#if defined(DEBUG_WOLFTPM) && !defined(WOLFTPM_NO_STD_HEADERS) && \
defined(WOLFTPM_HAVE_MONOTONIC_MS)
#define WOLFTPM_TIS_PROGRESS
word32 secs; /* whole seconds already marked with a dot */
#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();
/* 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)
{
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
word32 elapsed;
#endif
if (to->tries > 0) {
to->tries--;
}
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
if (to->haveStart) {
/* unsigned subtraction stays correct across the word32 wrap */
elapsed = (word32)(XTPM_GET_TIMEMS() - to->start);
if (elapsed >= TPM_TIMEOUT_MS) {
return 1;
}
#ifdef WOLFTPM_TIS_PROGRESS
/* Waits of a minute or more are normal for key generation, so show a
* dot per second rather than let a slow command look like a hang. */
if (elapsed / 1000u > to->secs) {
to->secs = elapsed / 1000u;
printf(".");
fflush(stdout);
}
#endif
/* A clock stuck at one value would never expire, so keep the
* iteration cap as a backstop for that case only. */
return (to->tries <= 0 && elapsed == 0) ? 1 : 0;
}
#endif
return (to->tries <= 0) ? 1 : 0;
}
#ifdef WOLFTPM_TIS_PROGRESS
/* End the dot line, if any were printed. */
static void TPM2_TIS_TimeoutDone(TPM2_TIS_TIMEOUT* to)
{
if (to->secs > 0) {
printf("\n");
fflush(stdout);
}
}
#else
#define TPM2_TIS_TimeoutDone(to) (void)(to)
#endif
#ifdef WOLFTPM_DEBUG_TIMEOUT
/* Elapsed ms where a clock exists, else polls taken. */
static word32 TPM2_TIS_TimeoutSpent(TPM2_TIS_TIMEOUT* to)
{
#ifdef WOLFTPM_HAVE_MONOTONIC_MS
if (to->haveStart) {
return (word32)(XTPM_GET_TIMEMS() - to->start);
}
#endif
return (word32)(TPM_TIMEOUT_TRIES - to->tries);
}
#endif
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);
TPM2_TIS_TimeoutDone(&to);
#ifdef WOLFTPM_DEBUG_TIMEOUT
printf("TIS_WaitForStatus: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
printf("TIS_WaitForStatus: spent %u\n",
(unsigned int)TPM2_TIS_TimeoutSpent(&to));
#endif
if (timeout <= 0)
if (expired)
return TPM_RC_TIMEOUT;
return rc;
}
@ -458,7 +551,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),
@ -469,16 +565,19 @@ 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);
TPM2_TIS_TimeoutDone(&to);
#ifdef WOLFTPM_DEBUG_TIMEOUT
printf("TIS_GetBurstCount: Timeout %d\n", TPM_TIMEOUT_TRIES - timeout);
printf("TIS_GetBurstCount: spent %u\n",
(unsigned int)TPM2_TIS_TimeoutSpent(&to));
#endif
if (*burstCount > MAX_SPI_FRAMESIZE)
*burstCount = MAX_SPI_FRAMESIZE;
if (timeout <= 0)
if (expired)
return TPM_RC_TIMEOUT;
}

View File

@ -1250,15 +1250,9 @@ int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* cap)
* Returns TPM_RC_SUCCESS with *isSupported set to 1 (supported) or 0 (not
* supported); on any failure a non-zero rc is returned and *isSupported is set
* to 0 so a caller that ignores the rc fails closed.
* Queries TPM_CAP_ALGS: the TPM returns algorithms with ID >= property, so a
* match at index 0 for a single-property query means it is implemented. */
* Delegates to TPM2_IsAlgSupported(); dev is validated but unused. */
int wolfTPM2_IsAlgSupported(WOLFTPM2_DEV* dev, TPM_ALG_ID alg, int* isSupported)
{
int rc;
GetCapability_In in;
GetCapability_Out out;
TPML_ALG_PROPERTY* algs;
if (isSupported == NULL) {
return BAD_FUNC_ARG;
}
@ -1267,29 +1261,7 @@ int wolfTPM2_IsAlgSupported(WOLFTPM2_DEV* dev, TPM_ALG_ID alg, int* isSupported)
if (dev == NULL) {
return BAD_FUNC_ARG;
}
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 rc; /* query failure, distinct from "not supported" */
}
/* capabilityData.data is a union - confirm the TPM answered with the
* capability we asked for before reading the algorithm member, so a
* non-conforming response cannot be reinterpreted as an algorithm
* property. */
if (out.capabilityData.capability != TPM_CAP_ALGS) {
return TPM_RC_VALUE;
}
/* The TPM returns algorithms with ID >= property; a match at index 0
* means the requested algorithm is implemented. */
algs = &out.capabilityData.data.algorithms;
if (algs->count >= 1 && algs->algProperties[0].alg == alg) {
*isSupported = 1;
}
return TPM_RC_SUCCESS;
return TPM2_IsAlgSupported(alg, isSupported);
}
int wolfTPM2_GetHandles(TPM_HANDLE handle, TPML_HANDLE* handles)
@ -5788,6 +5760,109 @@ int wolfTPM2_SignHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
}
/* Reject a signature the TPM cannot accept as a parameter. Some parts stop
* responding until a hardware reset rather than erroring, so this must not be
* left to the TPM. Two limits apply: TPM_PT_INPUT_BUFFER bounds the parameter
* and TPM_PT_MAX_COMMAND_SIZE bounds the whole command, so the capability read
* is skipped only when the signature plus overhead fits inside
* TPM_MIN_INPUT_BUFFER, the floor every conformant TPM meets. That still
* covers every ECC signature and RSA up to 4096. Above it the limit must be
* established, so this fails closed. Returns TPM_RC_SUCCESS if it fits,
* BUFFER_E if it provably does not, and the query error otherwise so callers
* can tell the two apart. */
/* Bytes that share the command with the signature: 10-byte header, up to two
* 4-byte handles, a 4-byte auth-area size, a password session (~9) or an HMAC
* session with a nonce and digest (~75), the digest TPM2B (up to 66), and the
* TPMT_SIGNATURE tag/alg/size fields (~8). Rounded up with margin. Only used
* to reserve room against TPM_PT_MAX_COMMAND_SIZE, so an over-estimate can
* reject a signature that would just fit; override if that ever bites. */
#ifndef TPM_SIG_CMD_OVERHEAD
#define TPM_SIG_CMD_OVERHEAD 176
#endif
static int wolfTPM2_CheckSigInputBuffer(int sigSz)
{
int rc;
GetCapability_In in;
GetCapability_Out out;
TPML_TAGGED_TPM_PROPERTY* props;
UINT32 inputBuffer;
if (sigSz < 0) {
return BUFFER_E;
}
/* Overhead is included: a signature that fits the parameter floor could
* still overflow a TPM whose command limit equals that floor. */
if ((UINT32)sigSz + TPM_SIG_CMD_OVERHEAD <= TPM_MIN_INPUT_BUFFER) {
return TPM_RC_SUCCESS;
}
XMEMSET(&in, 0, sizeof(in));
XMEMSET(&out, 0, sizeof(out));
in.capability = TPM_CAP_TPM_PROPERTIES;
in.property = TPM_PT_INPUT_BUFFER;
in.propertyCount = 1;
rc = TPM2_GetCapability(&in, &out);
if (rc != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFTPM
printf("Signature size check: cannot read TPM_PT_INPUT_BUFFER "
"(0x%x), refusing a %d byte signature\n", rc, sigSz);
#endif
return rc; /* query failure, distinct from a genuine oversize */
}
/* union - confirm the capability and property asked for */
props = &out.capabilityData.data.tpmProperties;
if (out.capabilityData.capability != TPM_CAP_TPM_PROPERTIES ||
props->count == 0 ||
props->tpmProperty[0].property != TPM_PT_INPUT_BUFFER) {
#ifdef DEBUG_WOLFTPM
printf("Signature size check: unexpected capability response, "
"refusing a %d byte signature\n", sigSz);
#endif
return TPM_RC_VALUE; /* not an oversize; the TPM answered wrongly */
}
inputBuffer = props->tpmProperty[0].value;
if (inputBuffer == 0) {
return TPM_RC_VALUE; /* nonsensical limit, treat as unreadable */
}
if ((UINT32)sigSz > inputBuffer) {
#ifdef DEBUG_WOLFTPM
printf("Signature size check: signature %d bytes exceeds the TPM's "
"%u byte input buffer\n", sigSz, (unsigned int)inputBuffer);
#endif
return BUFFER_E;
}
/* Also check the whole command fits; some parts report both the same.
* Not reporting this limit is not penalised, the check above bounded it. */
XMEMSET(&in, 0, sizeof(in));
XMEMSET(&out, 0, sizeof(out));
in.capability = TPM_CAP_TPM_PROPERTIES;
in.property = TPM_PT_MAX_COMMAND_SIZE;
in.propertyCount = 1;
rc = TPM2_GetCapability(&in, &out);
if (rc == TPM_RC_SUCCESS &&
out.capabilityData.capability == TPM_CAP_TPM_PROPERTIES) {
props = &out.capabilityData.data.tpmProperties;
if (props->count > 0 &&
props->tpmProperty[0].property == TPM_PT_MAX_COMMAND_SIZE &&
props->tpmProperty[0].value > 0 &&
(UINT32)sigSz + TPM_SIG_CMD_OVERHEAD >
props->tpmProperty[0].value) {
#ifdef DEBUG_WOLFTPM
printf("Signature size check: signature %d bytes plus overhead "
"exceeds the TPM's %u byte command limit\n", sigSz,
(unsigned int)props->tpmProperty[0].value);
#endif
return BUFFER_E;
}
}
return TPM_RC_SUCCESS;
}
/* sigAlg: TPM_ALG_RSASSA, TPM_ALG_RSAPSS, TPM_ALG_ECDSA or TPM_ALG_ECDAA */
/* hashAlg: TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384 or TPM_ALG_SHA512 */
int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
@ -5805,6 +5880,11 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
return BAD_FUNC_ARG;
}
rc = wolfTPM2_CheckSigInputBuffer(sigSz);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
if (key->pub.publicArea.type == TPM_ALG_ECC) {
if (sigAlg == TPM_ALG_NULL)
sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme;
@ -6234,6 +6314,13 @@ int wolfTPM2_VerifySequenceComplete(WOLFTPM2_DEV* dev,
return BAD_FUNC_ARG;
}
/* Before the sequence is advanced: bailing out after SequenceUpdate
* would leave the sequence slot allocated. */
rc = wolfTPM2_CheckSigInputBuffer(sigSz);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
/* Validate per-key-type sigSz BEFORE the internal SequenceUpdate
* call. Otherwise we advance the TPM-side sequence and then bail out
* before Complete, leaving the slot allocated until the caller
@ -6521,6 +6608,11 @@ int wolfTPM2_VerifyDigestSignature(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
return BAD_FUNC_ARG;
}
rc = wolfTPM2_CheckSigInputBuffer(sigSz);
if (rc != TPM_RC_SUCCESS) {
return rc;
}
XMEMSET(&verifyDigestSigIn, 0, sizeof(verifyDigestSigIn));
verifyDigestSigIn.keyHandle = key->handle.hndl;
verifyDigestSigIn.digest.size = (UINT16)digestSz;

View File

@ -1408,6 +1408,55 @@ static void test_wolfTPM2_IsAlgSupported(void)
#endif /* WOLFTPM_SWTPM */
}
/* TPM2_IsPcrBankAllocated: argument validation always, plus a live query on
* the simulator. Mirrors test_wolfTPM2_IsAlgSupported. */
static void test_TPM2_IsPcrBankAllocated(void)
{
int isAllocated = 1; /* seeded true to prove the error paths clear it */
#if defined(WOLFTPM_SWTPM)
int rc;
WOLFTPM2_DEV dev;
#endif
/* NULL out-param */
AssertIntEQ(TPM2_IsPcrBankAllocated(TPM_ALG_SHA256, 0, NULL),
BAD_FUNC_ARG);
/* negative index must fail and must not leave the out-param set */
AssertIntEQ(TPM2_IsPcrBankAllocated(TPM_ALG_SHA256, -1, &isAllocated),
BAD_FUNC_ARG);
AssertIntEQ(isAllocated, 0);
#if defined(WOLFTPM_SWTPM)
XMEMSET(&dev, 0, sizeof(dev));
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
AssertIntEQ(rc, 0);
/* Every TPM 2.0 part allocates a SHA2-256 bank covering PCR 0 */
isAllocated = 0;
AssertIntEQ(TPM2_IsPcrBankAllocated(TPM_ALG_SHA256, 0, &isAllocated),
TPM_RC_SUCCESS);
AssertIntEQ(isAllocated, 1);
/* A hash no bank uses reports not-allocated, with a success rc because
* the query itself worked - the distinction this API exists to make. */
isAllocated = 1;
AssertIntEQ(TPM2_IsPcrBankAllocated((TPM_ALG_ID)0x7FFF, 0, &isAllocated),
TPM_RC_SUCCESS);
AssertIntEQ(isAllocated, 0);
/* An index beyond the PCR count is not allocated in any bank */
isAllocated = 1;
AssertIntEQ(TPM2_IsPcrBankAllocated(TPM_ALG_SHA256, 250, &isAllocated),
TPM_RC_SUCCESS);
AssertIntEQ(isAllocated, 0);
wolfTPM2_Cleanup(&dev);
printf("Test PcrBank: %-40s Passed\n", "Args + Query:");
#else
printf("Test PcrBank: %-40s Passed\n", "Arg Validation:");
#endif /* WOLFTPM_SWTPM */
}
/* Success path for wolfTPM2_PolicyOR: satisfy one branch of a real two-branch
* OR on a live policy session and confirm the TPM's running policy digest
* matches the offline computation. Simulator only. */
@ -2847,6 +2896,31 @@ static void test_WOLFTPM_IS_COMMAND_UNAVAILABLE(void)
AssertIntEQ(0, WOLFTPM_IS_COMMAND_UNAVAILABLE(0x00000343)); /* layer bits */
AssertIntEQ(0, WOLFTPM_IS_COMMAND_UNAVAILABLE(0x000b0142)); /* vendor, non-cc */
/* A command that exists but is switched off answers TPM_RC_DISABLED, which
* must not be confused with an absent one. Same masking and >= 0 gate. */
AssertIntNE(0, WOLFTPM_IS_COMMAND_DISABLED((int)TPM_RC_DISABLED));
AssertIntNE(0, WOLFTPM_IS_COMMAND_DISABLED(0x000b0120)); /* vendor bits */
AssertIntEQ(0, WOLFTPM_IS_COMMAND_DISABLED((int)TPM_RC_COMMAND_CODE));
AssertIntEQ(0, WOLFTPM_IS_COMMAND_DISABLED((int)TPM_RC_SUCCESS));
AssertIntEQ(0, WOLFTPM_IS_COMMAND_DISABLED(-189));
AssertIntEQ(0, WOLFTPM_IS_COMMAND_DISABLED(-1));
/* The combined form accepts either, and nothing else. */
AssertIntNE(0,
WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED((int)TPM_RC_COMMAND_CODE));
AssertIntNE(0,
WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED((int)TPM_RC_DISABLED));
AssertIntEQ(0,
WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED((int)TPM_RC_SUCCESS));
AssertIntEQ(0, WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(-189));
/* The shared base macro underlying all three. Note TPM_RC_VALUE is not
* usable here: tpm2_asn.h defines it as an ASN error (-203), shadowing the
* response code of the same name from tpm2.h in this translation unit. */
AssertIntNE(0, WOLFTPM_RC_IS((int)TPM_RC_DISABLED, TPM_RC_DISABLED));
AssertIntEQ(0, WOLFTPM_RC_IS((int)TPM_RC_DISABLED, TPM_RC_COMMAND_CODE));
AssertIntEQ(0, WOLFTPM_RC_IS(-189, TPM_RC_DISABLED));
printf("Test TPM Wrapper: %-40s Passed\n", "IsCommandUnavailable:");
}
@ -9527,6 +9601,7 @@ int unit_tests(int argc, char *argv[])
test_wolfTPM2_FirmwareUpgrade_ex_session();
#endif
test_wolfTPM2_IsAlgSupported();
test_TPM2_IsPcrBankAllocated();
test_wolfTPM2_PolicyOR_success();
#if defined(WOLFTPM_MLDSA) && defined(WOLFTPM_MLKEM)
/* Run non-TPM-dependent tests first */

View File

@ -744,6 +744,10 @@ typedef enum {
} TPM_PT_T;
typedef UINT32 TPM_PT;
/* Smallest TPM_PT_INPUT_BUFFER a conformant TPM may report (TCG Part 2), so a
* parameter at or below it fits without reading the capability. */
#define TPM_MIN_INPUT_BUFFER 1024
/* PCR Property Tag */
typedef enum {
TPM_PT_PCR_FIRST = 0x00000000,
@ -2201,21 +2205,35 @@ struct wolfTPM_winContext {
#define TPM_E_COMMAND_BLOCKED (0x80280400)
#endif
/* Mask off vendor/layer high bits so a vendor-decorated TPM_RC_COMMAND_CODE
* (e.g. NS350 returns 0x000b0143 for 0x143) still matches. Gate on >= 0 so a
* propagated negative wolfCrypt error (e.g. -189) is never misread as an
* unavailable command. TPM_E_COMMAND_BLOCKED is a Windows HRESULT (negative),
* matched exactly. */
#define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) \
(((code) >= 0 && \
(((UINT32)(code)) & 0xFFFFu) == (UINT32)TPM_RC_COMMAND_CODE) || \
(code) == (int)TPM_E_COMMAND_BLOCKED)
#else
#define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) \
((code) >= 0 && \
(((UINT32)(code)) & 0xFFFFu) == (UINT32)TPM_RC_COMMAND_CODE)
#endif /* WOLFTPM_WINAPI */
/* Compare a return code against a TPM_RC, masking off vendor/layer high bits
* so a vendor-decorated code (NS350 returns 0x000b0143 for 0x143) still
* matches. Gate on >= 0 so a propagated negative wolfCrypt error (e.g. -189)
* is never misread as a TPM response code. */
#define WOLFTPM_RC_IS(code, rc) \
((code) >= 0 && (((UINT32)(code)) & 0xFFFFu) == (UINT32)(rc))
/* The TPM does not implement this command. TPM_E_COMMAND_BLOCKED is a Windows
* HRESULT (negative), so it is matched exactly rather than masked. */
#ifdef WOLFTPM_WINAPI
#define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) \
(WOLFTPM_RC_IS(code, TPM_RC_COMMAND_CODE) || \
(code) == (int)TPM_E_COMMAND_BLOCKED)
#else
#define WOLFTPM_IS_COMMAND_UNAVAILABLE(code) \
WOLFTPM_RC_IS(code, TPM_RC_COMMAND_CODE)
#endif
/* Implemented but switched off, commonly TPM2_EncryptDecrypt for export
* controls; answers TPM_RC_DISABLED not TPM_RC_COMMAND_CODE. */
#define WOLFTPM_IS_COMMAND_DISABLED(code) \
WOLFTPM_RC_IS(code, TPM_RC_DISABLED)
/* Either form of "the TPM will not run this command". */
#define WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(code) \
(WOLFTPM_IS_COMMAND_UNAVAILABLE(code) || WOLFTPM_IS_COMMAND_DISABLED(code))
/* make sure advanced IO is enabled for I2C */
#ifdef WOLFTPM_I2C
#undef WOLFTPM_ADV_IO
@ -4135,6 +4153,46 @@ WOLFTPM_API void TPM2_SetupPCRSel(TPML_PCR_SELECTION* pcr, TPM_ALG_ID alg,
WOLFTPM_API void TPM2_SetupPCRSelArray(TPML_PCR_SELECTION* pcr, TPM_ALG_ID alg,
byte* pcrArray, word32 pcrArraySz);
/*!
\ingroup TPM2_Proprietary
\brief Report whether the TPM implements a given algorithm
\note Queries TPM_CAP_ALGS. Fails closed: *isSupported is 0 on any error,
so a query failure cannot be mistaken for "supported".
\return TPM_RC_SUCCESS: query completed; *isSupported is 1 or 0
\return BAD_FUNC_ARG: isSupported is NULL
\param alg the algorithm identifier to test (for example TPM_ALG_SHA512)
\param isSupported output, set to 1 if implemented by the TPM, else 0
\sa TPM2_IsPcrBankAllocated
*/
WOLFTPM_API int TPM2_IsAlgSupported(TPM_ALG_ID alg, int* isSupported);
/*!
\ingroup TPM2_Proprietary
\brief Report whether a PCR index is allocated in a bank of a given hash
\note Queries TPM_CAP_PCRS. Implementing a hash and allocating a bank for
it are separate: a TPM may offer SHA-1 while allocating no SHA-1
bank, and a selection naming an unallocated bank is rejected. Ask
before building a selection with TPM2_SetupPCRSel(). Fails closed:
*isAllocated is 0 on any error.
\return TPM_RC_SUCCESS: query completed; *isAllocated is 1 or 0
\return BAD_FUNC_ARG: isAllocated is NULL or pcrIndex is negative
\param hashAlg the PCR bank hash algorithm (for example TPM_ALG_SHA256)
\param pcrIndex the PCR index to test
\param isAllocated output, set to 1 if allocated in that bank, else 0
\sa TPM2_SetupPCRSel
\sa TPM2_IsAlgSupported
*/
WOLFTPM_API int TPM2_IsPcrBankAllocated(TPM_ALG_ID hashAlg, int pcrIndex,
int* isAllocated);
/*!
\ingroup TPM2_Proprietary
\brief Get a human readable string for any TPM 2.0 return code

View File

@ -35,11 +35,26 @@
#define MAX_CERT_SZ 2048
#endif
/* ASN Error Codes */
#define TPM_RC_ASN_PARSE (-201) /* ASN parsing error */
#define TPM_RC_INSUFFICIENT (-202) /* ASN insufficient data */
#define TPM_RC_VALUE (-203) /* ASN value error (invalid tag) */
#define TPM_RC_BUFFER (-204) /* ASN buffer error */
/* ASN Error Codes.
* Spelled TPM_RC_ASN_* so they cannot shadow the TPM response codes of the
* same short name in tpm2.h: TPM_RC_VALUE there is an enum equal to 0x084 and
* TPM_RC_INSUFFICIENT is 0x09A. Because those are enum constants rather than
* macros, a #ifndef guard cannot see them, so any file including both headers
* silently got the ASN meaning. */
#define TPM_RC_ASN_PARSE (-201) /* ASN parsing error */
#define TPM_RC_ASN_INSUFFICIENT (-202) /* ASN insufficient data */
#define TPM_RC_ASN_VALUE (-203) /* ASN value error (invalid tag) */
#define TPM_RC_ASN_BUFFER (-204) /* ASN buffer error */
/* Deprecated short spellings, kept so existing callers still build. They
* shadow the tpm2.h response codes of the same name, so prefer the
* TPM_RC_ASN_* forms above. Define WOLFTPM_NO_DEPRECATED_ASN_RC to drop them
* and get the tpm2.h meanings instead. */
#ifndef WOLFTPM_NO_DEPRECATED_ASN_RC
#define TPM_RC_INSUFFICIENT TPM_RC_ASN_INSUFFICIENT
#define TPM_RC_VALUE TPM_RC_ASN_VALUE
#define TPM_RC_BUFFER TPM_RC_ASN_BUFFER
#endif
/* ASN.1 Constants */
enum {
@ -78,7 +93,7 @@ typedef struct DecodedX509 {
\param inOutIdx Current position in buffer, updated to new position
\param len Decoded length value
\param maxIdx Maximum allowed index in buffer
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
\return Length on success, TPM_RC_ASN_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx,
int* len, word32 maxIdx);
@ -91,7 +106,7 @@ WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx,
\param len Decoded length value
\param maxIdx Maximum allowed index in buffer
\param check Flag to enable length validation
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
\return Length on success, TPM_RC_ASN_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx,
int* len, word32 maxIdx, int check);
@ -104,7 +119,7 @@ WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx,
\param inOutIdx Current position in buffer, updated to new position
\param tag_len Decoded length value
\param tag Expected ASN.1 tag value
\return 0 on success, TPM_RC_INSUFFICIENT on buffer error, TPM_RC_VALUE on tag mismatch
\return 0 on success, TPM_RC_ASN_INSUFFICIENT on buffer error, TPM_RC_ASN_VALUE on tag mismatch
*/
WOLFTPM_API int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz,
int* inOutIdx, int* tag_len, uint8_t tag);
@ -114,8 +129,8 @@ WOLFTPM_API int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz,
\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_ASN_VALUE on invalid input,
TPM_RC_ASN_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz);
@ -124,7 +139,7 @@ WOLFTPM_API int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz);
\param input Buffer containing ASN.1 encoded X.509 certificate
\param inputSz Size of input buffer
\param x509 Structure to store decoded certificate data
\return 0 on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
\return 0 on success, TPM_RC_ASN_VALUE on invalid input, TPM_RC_ASN_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
DecodedX509* x509);
@ -135,8 +150,8 @@ WOLFTPM_API int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
\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_ASN_VALUE on invalid input,
TPM_RC_ASN_INSUFFICIENT on buffer error
*/
WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz,
TPM2B_PUBLIC* pub);
@ -150,7 +165,7 @@ WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz,
\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
\return 0 on success, TPM_RC_ASN_VALUE on invalid padding
*/
WOLFTPM_API int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz);

View File

@ -716,6 +716,56 @@ typedef int64_t INT64;
#endif
#endif
/* Monotonic ms tick for the TIS wait loops. Wraps ~49 days, so compare with
* unsigned subtraction. WOLFTPM_HAVE_MONOTONIC_MS is set only where a clock
* exists, port-supplied included; otherwise the iteration counter is kept.
* WOLFTPM_NO_MONOTONIC_MS forces the counter. */
#ifndef WOLFTPM_NO_MONOTONIC_MS
/* Without this a port-supplied hook would be silently ignored. */
#ifdef XTPM_GET_TIMEMS
#define WOLFTPM_HAVE_MONOTONIC_MS
#elif !defined(WOLFTPM_NO_STD_HEADERS)
#if defined(WOLFTPM_ZEPHYR)
#include <zephyr/kernel.h>
#define XTPM_GET_TIMEMS() ((word32)k_uptime_get())
#define WOLFTPM_HAVE_MONOTONIC_MS
#elif defined(WOLFSSL_ESPIDF) || defined(FREERTOS)
#define XTPM_GET_TIMEMS() \
((word32)xTaskGetTickCount() * (word32)portTICK_PERIOD_MS)
#define WOLFTPM_HAVE_MONOTONIC_MS
#elif defined(_WIN32)
#include <windows.h>
#define XTPM_GET_TIMEMS() ((word32)GetTickCount64())
#define WOLFTPM_HAVE_MONOTONIC_MS
#else
/* Include first, then feature-test: strict C99 may not expose
* CLOCK_MONOTONIC, and __linux__ alone would fail to compile. */
#include <time.h>
#if defined(CLOCK_MONOTONIC) && \
(!defined(_POSIX_TIMERS) || _POSIX_TIMERS > 0)
static inline word32 XTPM_GET_TIMEMS(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
return (word32)((word32)ts.tv_sec * 1000u +
(word32)(ts.tv_nsec / 1000000L));
}
#define WOLFTPM_HAVE_MONOTONIC_MS
#endif
#endif
#endif /* XTPM_GET_TIMEMS */
#endif /* !WOLFTPM_NO_MONOTONIC_MS */
/* Must cover the slowest single command. RSA-2048 key generation has been
* measured at 89 s on a current part, so this leaves roughly 2x headroom. */
#ifndef TPM_TIMEOUT_MS
#define TPM_TIMEOUT_MS 180000
#endif
#ifndef BUFFER_ALIGNMENT
#define BUFFER_ALIGNMENT 4
#endif