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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ examples/pcr/extend
examples/pcr/policy
examples/pcr/policy_sign
examples/pcr/reset
examples/pcr/allocate
examples/timestamp/clock_set
examples/management/flush
examples/management/tpmclear
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ if (WOLFTPM_EXAMPLES AND BUILD_WOLFTPM_LIB)
add_tpm_example(quote pcr/quote.c)
add_tpm_example(read_pcr pcr/read_pcr.c)
add_tpm_example(reset pcr/reset.c)
add_tpm_example(allocate pcr/allocate.c)
add_tpm_example(pkcs7 pkcs7/pkcs7.c)
add_tpm_example(seal seal/seal.c)
add_tpm_example(unseal seal/unseal.c)
Expand Down
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Unreleased

* Added `wolfTPM2_AllocatePCRBanks` for changing which PCR banks a TPM allocates.
- Added `examples/pcr/allocate` to report and re-provision the banks.
- Fixed the fwTPM applying the allocation immediately instead of at the next
`Startup(CLEAR)` per TPM 2.0 Part 3 22.5, accepting a selection that would
leave it with no PCR banks, ignoring the `pcrSelect` bitmap, and reporting
no allocated banks after a restart against an existing NV file.
* Added SPDM transport-bound TPM policies (PR #594).
- Added `TPM2_PolicyTransportSPDM` client support and fwTPM enforcement.
- Added SPDM-bound NV policy examples and tests.
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ More information about how to test and use PCR attestation can be found in the i
`./examples/pcr/quote`
`./examples/pcr/extend`
`./examples/pcr/reset`
`./examples/pcr/allocate`

### Remote Attestation challenge

Expand Down
78 changes: 71 additions & 7 deletions examples/bench/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,44 @@
#define TPM2_BENCH_DURATION_KEYGEN_SEC 15
static int gUseBase2 = 1;

/* Fixed-iteration mode (-iter=N). Zero keeps the default duration mode, where
* each algorithm runs for a wall-clock budget instead of a set count. */
static int gBenchIter = 0;
/* Per-iteration spread, so a single slow outlier is visible rather than
* averaged away. Rejection sampling makes ML-DSA signing vary run to run. */
static double gIterPrev, gIterMin, gIterMax;

static inline void bench_stats_start(int* count, double* start)
{
*count = 0;
*start = gettime_secs(1);
gIterPrev = *start;
gIterMin = 0;
gIterMax = 0;
}

static inline int bench_stats_check(double start, int* count, double maxDurSec)
{
double now, each;

(*count)++;
return ((gettime_secs(0) - start) < maxDurSec);
now = gettime_secs(0);
each = now - gIterPrev;
gIterPrev = now;
if (*count == 1) {
gIterMin = each;
gIterMax = each;
}
else if (each > gIterMax) {
gIterMax = each;
}
else if (each < gIterMin) {
gIterMin = each;
}
if (gBenchIter > 0) {
return (*count < gBenchIter);
}
return ((now - start) < maxDurSec);
}

/* countSz is number of bytes that 1 count represents. Normally bench_size,
Comment thread
dgarske marked this conversation as resolved.
Expand Down Expand Up @@ -105,8 +133,14 @@ static void bench_stats_sym_finish(const char* desc, int count, int countSz,
}

/* format and print to terminal */
printf("%-16s %5.0f %s took %5.3f seconds, %8.3f %s/s\n",
printf("%-16s %5.0f %s took %5.3f seconds, %8.3f %s/s",
desc, blocks, blockType, total, persec, blockType);
if (gBenchIter > 0) {
printf(", %d ops, avg %5.3f ms, min %5.3f ms, max %5.3f ms",
count, (count > 0) ? (total / count) * 1000 : 0,
gIterMin * 1000, gIterMax * 1000);
}
printf("\n");
}

static void bench_stats_asym_finish(const char* algo, int strength,
Expand All @@ -121,15 +155,21 @@ static void bench_stats_asym_finish(const char* algo, int strength,
milliEach = each * 1000; /* milliseconds */

printf("%-6s %5d %-9s %6d ops took %5.3f sec, avg %5.3f ms,"
" %.3f ops/sec\n", algo, strength, desc,
" %.3f ops/sec", algo, strength, desc,
count, total, milliEach, opsSec);
if (gBenchIter > 0) {
printf(", min %5.3f ms, max %5.3f ms",
gIterMin * 1000, gIterMax * 1000);
}
printf("\n");
}

/* True if rc means the TPM does not implement the operation (so the bench
* can skip it instead of aborting). Masks parameter bits on FMT1 codes. */
static int bench_unsupported(int rc)
{
return ((rc & 0xBF) == TPM_RC_SCHEME) || WOLFTPM_IS_COMMAND_UNAVAILABLE(rc);
return ((rc & 0xBF) == TPM_RC_SCHEME) ||
WOLFTPM_IS_COMMAND_UNAVAILABLE_OR_DISABLED(rc);
}

/* Print timing on success, "Skipped" if the op was not implemented. Returns
Expand All @@ -145,6 +185,14 @@ static int bench_asym_done(const char* algo, int strength, const char* desc,
printf("%-6s %5d %-9s Skipped (not supported)\n", algo, strength, desc);
return 0;
}
/* A post-quantum signature can exceed the TPM's input buffer, which the
* verify guard reports before sending. That is a property of the part,
* not a benchmark failure, so record it and carry on. */
if (rc == BUFFER_E) {
printf("%-6s %5d %-9s Skipped (signature exceeds TPM input buffer)\n",
algo, strength, desc);
return 0;
}
return rc;
}

Expand Down Expand Up @@ -203,9 +251,10 @@ static int bench_sym_aes(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* storageKey,
XMEMSET(iv, 0, sizeof(iv));
rc = wolfTPM2_EncryptDecrypt(dev, &aesKey, in, out, inOutSz, iv,
sizeof(iv), isDecrypt);
if (WOLFTPM_IS_COMMAND_UNAVAILABLE(rc)) {
printf("Encrypt/Decrypt unavailable\n");
break;
if (bench_unsupported(rc)) {
printf("%-16s Skipped (not supported)\n", desc);
rc = 0;
goto exit;
}
if (rc != 0) goto exit;
} while (bench_stats_check(start, &count, maxDuration));
Expand Down Expand Up @@ -368,6 +417,9 @@ static void usage(void)
printf("* -aes/xor: Use Parameter Encryption\n");
printf("* -maxdur=[ms]: Maximum runtime for each algorithm in milliseconds "
"(default %d)\n", TPM2_BENCH_DURATION_SEC*1000);
printf("* -iter=[n]: Run each algorithm exactly n times and report the\n");
printf(" average with the per-iteration min and max, instead of\n");
printf(" running for a duration. Overrides -maxdur.\n");
}

/******************************************************************************/
Expand Down Expand Up @@ -398,6 +450,9 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
double maxDuration = TPM2_BENCH_DURATION_SEC;
double maxKeyGenDurSec = TPM2_BENCH_DURATION_KEYGEN_SEC;

/* Static, so a previous call with -iter must not leak into this one */
gBenchIter = 0;

if (argc >= 2) {
if (XSTRCMP(argv[1], "-?") == 0 ||
XSTRCMP(argv[1], "-h") == 0 ||
Expand All @@ -417,6 +472,15 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
const char* maxStr = argv[argc-1] + XSTRLEN("-maxdur=");
maxKeyGenDurSec = maxDuration = XATOI(maxStr) / 1000.0;
}
else if (XSTRNCMP(argv[argc-1], "-iter=", XSTRLEN("-iter=")) == 0) {
const char* iterStr = argv[argc-1] + XSTRLEN("-iter=");
gBenchIter = XATOI(iterStr);
Comment thread
dgarske marked this conversation as resolved.
if (gBenchIter <= 0) {
printf("Iteration count must be greater than zero\n");
usage();
return BAD_FUNC_ARG;
}
}
else {
printf("Warning: Unrecognized option: %s\n", argv[argc-1]);
}
Expand Down
85 changes: 63 additions & 22 deletions examples/native/native_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -709,6 +710,19 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
}
printf("TPM2_ReadClock: success\n");

/* TEST_WRAP_DIGEST is SHA-1 on some targets, and a TPM that allocates no
* SHA-1 bank would abort every PCR step below. Check once, up front. */
rc = TPM2_IsPcrBankAllocated(TEST_WRAP_DIGEST, 0, &isAllocated);
if (rc != TPM_RC_SUCCESS) {
printf("TPM2_IsPcrBankAllocated failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
goto exit;
}
if (!isAllocated) {
printf("PCR tests skipped (no 0x%x PCR bank allocated)\n",
(unsigned int)TEST_WRAP_DIGEST);
goto pcr_tests_done;
}

/* PCR Read */
for (i=0; i<pcrCount; i++) {
Expand Down Expand Up @@ -804,6 +818,8 @@ int TPM2_Native_TestArgs(void* userCtx, int argc, char *argv[])
}
#endif /* !WOLFTPM_WINAPI */

pcr_tests_done:

/* Start Auth Session */
XMEMSET(&cmdIn.authSes, 0, sizeof(cmdIn.authSes));
cmdIn.authSes.tpmKey = TPM_RH_NULL;
Expand Down Expand Up @@ -863,22 +879,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 */
Expand All @@ -892,20 +920,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;
Expand Down Expand Up @@ -1635,7 +1674,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;
Expand All @@ -1657,7 +1696,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) {
Expand All @@ -1673,7 +1714,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;
}
Expand Down
Loading
Loading