mirror of https://github.com/wolfSSL/wolfTPM.git
Merge 9afde207aa into 4947973367
commit
a755c8254f
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
82
src/tpm2.c
82
src/tpm2.c
|
|
@ -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 -- */
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
115
src/tpm2_tis.c
115
src/tpm2_tis.c
|
|
@ -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, ®);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
152
src/tpm2_wrap.c
152
src/tpm2_wrap.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue