Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .github/workflows/make-test-swtpm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ jobs:
# STMicro ST33KTPM2
- name: st33ktpm2 firmware
wolftpm_config: --enable-st33 --enable-firmware --disable-fwtpm
# HAL nRST reset control (compile-only, no GPIO hardware in CI)
- name: hal-reset
wolftpm_config: --enable-st33 --enable-hal-reset --disable-fwtpm
test_command: "true"
# SPDM + Nuvoton (compile-only, no hardware in CI)
- name: spdm-nuvoton
wolfssl_config: --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,11 @@ examples/firmware/*.MANIFESTHASH
# Firmware TPM files
src/fwtpm/fwtpm_server
fwtpm_nv.bin
fwtpm_nv.bin.key
fwtpm_test_nv.bin
fwtpm_test_nv.bin.key
# Catch any NV integrity-key sidecar the fwTPM auto-generates
*.bin.key

# Fuzz artifacts (corpus generated at runtime by gen_corpus.py)
tests/fuzz/corpus/
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,10 @@ TLS_BENCH_MODE Enables TLS benchmarking mode.
NO_TPM_BENCH Disables the TPM benchmarking example.
WOLFTPM_MAX_RETRIES Default number of times a command is transparently resubmitted when the TPM returns TPM_RC_RETRY (momentarily busy, e.g. persisting the daUsed flag on first auth use of an externally provisioned non-noDA AIK/SUDI key). Disabled by default (0); opt in with TPM2_SetCommandRetries() at runtime or -DWOLFTPM_MAX_RETRIES=N at build time. wolfTPM's own key templates set noDA and never trigger it.
WOLFTPM_NO_RETRY Compiles out the TPM_RC_RETRY auto-resubmit handling entirely; TPM_RC_RETRY is returned to the caller for manual handling.
WOLFTPM_LOCALITY_DEFAULT Default TIS locality requested at startup (default 0). Runtime override via wolfTPM2_SetLocality() on SPI/memory-mapped and swtpm transports. The I2C HAL addresses only locality 0 (the TIS locality lives in address bits 12+, which the 8-bit I2C register address cannot carry), so a non-zero wolfTPM2_SetLocality() on I2C returns NOT_COMPILED_IN rather than silently operating at locality 0.
WOLFTPM_TIS_RESET_STALE_LOCALITY At startup, release any other active locality so the default can be granted - recovers a wedge left when a prior session did not return to locality 0. Off by default; single-master buses only, since on a shared bus it could clear a locality another master holds (or use the nRST reset HAL to recover).
WOLFTPM_LOCALITY_TIMEOUT_TRIES Poll attempts when requesting a locality at runtime (default 1000). Kept small so a locality that cannot be granted fails fast.
WOLFTPM_RESET_LINE nRST GPIO line number for the optional reset HAL; set via --enable-hal-reset=LINE and driven with TPM2_IoCb_Reset() (see hal/README.md).
```

Note: For the I2C support on Raspberry Pi you may need to enable I2C. Here are the steps:
Expand Down Expand Up @@ -401,6 +405,8 @@ make

Note: The `--enable-firmware` option enables firmware upgrade support for ST33 TPMs. This adds the `st33_fw_update` example tool for performing firmware updates.

Raspberry Pi wiring: ST33KTPM2X SPI is on `/dev/spidev0.0` with `nRST` (active low) on GPIO24 (pin 18); Nuvoton uses GPIO4. Optionally drive nRST from code with `--enable-hal-reset` and `TPM2_IoCb_Reset()` (see `hal/README.md`).

### Building Microchip ATTPM20

Build wolfTPM:
Expand Down
29 changes: 29 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,34 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_ST33"
fi

# Optional TPM hardware reset (nRST) HAL control via Linux GPIO char device.
# Accepts an optional GPIO line number (default ST33 GPIO24 / Pi pin 18, Nuvoton GPIO4).
AC_ARG_ENABLE([hal-reset],
[AS_HELP_STRING([--enable-hal-reset@<:@=LINE@:>@],[Enable TPM nRST reset HAL (optional GPIO line; default ST33 GPIO24, Nuvoton GPIO4) (default: disabled)])],
[ ENABLED_HAL_RESET=$enableval ],
[ ENABLED_HAL_RESET=no ]
)
if test "x$ENABLED_HAL_RESET" != "xno"
Comment thread
dgarske marked this conversation as resolved.
then
# The reset HAL implementation (hal/tpm_io.c) only builds for the SPI/I2C
# example HAL, not the native kernel (/dev/tpm0) or swtpm transports, so
# reject those combinations rather than report "yes" with no callable API.
# Note swtpm is the default on Linux x86_64/aarch64, so the hardware reset
# HAL requires explicitly selecting a hardware interface (--enable-spi/-i2c).
if test "x$ENABLED_DEVTPM" = "xyes" || test "x$ENABLED_SWTPM" = "xyes" || test "x$ENABLED_SWTPM" = "xuart"
then
AC_MSG_ERROR([--enable-hal-reset needs the SPI/I2C hardware HAL; it is not available with the swtpm simulator (default on Linux x86_64/aarch64) or --enable-devtpm. Select a hardware interface, e.g. --enable-spi or --enable-i2c.])
fi
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_HAL_RESET"
case "x$ENABLED_HAL_RESET" in
xyes) ;;
x|x*[[!0-9]]*)
AC_MSG_ERROR([--enable-hal-reset=LINE requires a numeric GPIO line number (e.g. --enable-hal-reset=24).]) ;;
*) AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_RESET_LINE=$ENABLED_HAL_RESET" ;;
esac
ENABLED_HAL_RESET=yes
fi

# Microchip ATTPM20
AC_ARG_ENABLE([mchp],,
[ ENABLED_MCHP=$enableval ],
Expand Down Expand Up @@ -1132,6 +1160,7 @@ if test "x$ENABLED_SWTPM" = "xyes"; then
fi
echo " * WINAPI: $ENABLED_WINAPI"
echo " * TIS/SPI Check Wait State: $ENABLED_CHECKWAITSTATE"
echo " * HAL Reset (nRST GPIO): $ENABLED_HAL_RESET"

echo " * Infineon SLB967X $ENABLED_INFINEON"
echo " * STM ST33: $ENABLED_ST"
Expand Down
9 changes: 7 additions & 2 deletions examples/pcr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Not all PCRs are equal. The user can perform `extend` operation on all PCRs, but
* PCR16 is a PCR for debug purposes. This is the PCR used by all tools above by default. It is safe to test and work with PCR16.
* PCR17-22 are reserved for Dynamic Root of Trust Measurement (DRTM), an advanced topic that is to be covered separately.

Reset locality (TCG PC Client): PCR16/23 reset at localities 0-3, PCR20-22 at locality 2-4, and PCR17-19 at locality 4. Use `-loc=n` to select the locality (see `wolfTPM2_SetLocality`); it applies to the built-in TIS/SPI driver and the fwTPM.

### Extend

The TPM 2.0 `TPM2_Extend` API uses a SHA1 or SHA256 cryptographic operation to combine the current value of the PCR and with newly provided hash digest.
Expand All @@ -50,10 +52,13 @@ The TPM 2.0 `TPM2_Quote` API is a standard operation that encapsulates the PCR d

```sh
$ ./examples/pcr/reset -?
Comment thread
dgarske marked this conversation as resolved.
PCR index is out of range (0-23)
Incorrect arguments
Expected usage:
./examples/pcr/reset [pcr]
./examples/pcr/reset [pcr] [-loc=n]
* pcr is a PCR index between 0-23 (default 16)
* -loc=n switch to TPM locality n (0-4) before reset
(PCR 17-19 need locality 4; 20-22 need locality 2-4;
enforced by the fwTPM and by discrete TPMs like the ST33)
Demo usage without parameters, resets PCR16.
```

Expand Down
60 changes: 47 additions & 13 deletions examples/pcr/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,19 @@
static void usage(void)
{
printf("Expected usage:\n");
printf("./examples/pcr/reset [pcr]\n");
printf("./examples/pcr/reset [pcr] [-loc=n]\n");
printf("* pcr is a PCR index between 0-23 (default %d)\n", TPM2_TEST_PCR);
printf("* -loc=n switch to TPM locality n (0-4) before reset\n");
Comment thread
dgarske marked this conversation as resolved.
printf(" (PCR 17-19 need locality 4; 20-22 need locality 2-4;\n");
printf(" enforced by the fwTPM and by discrete TPMs like the ST33)\n");
printf("Demo usage without parameters, resets PCR%d.\n", TPM2_TEST_PCR);
}

int TPM2_PCR_Reset_Test(void* userCtx, int argc, char *argv[])
{
int i, j, pcrIndex = TPM2_TEST_PCR, rc = -1;
int locality = -1; /* -1 means leave at default locality */
int localitySwitched = 0;
WOLFTPM2_DEV dev;

union {
Expand All @@ -63,22 +68,32 @@ int TPM2_PCR_Reset_Test(void* userCtx, int argc, char *argv[])
byte maxOutput[MAX_RESPONSE_SIZE];
} cmdOut;

if (argc == 2) {
pcrIndex = XATOI(argv[1]);
if (pcrIndex < 0 || pcrIndex > 23 || *argv[1] < '0' || *argv[1] > '9') {
printf("PCR index is out of range (0-23)\n");
/* Parse arguments: an optional PCR index and an optional -loc=n flag */
Comment thread
dgarske marked this conversation as resolved.
for (i = 1; i < argc; i++) {
if (XSTRNCMP(argv[i], "-loc=", 5) == 0) {
/* Require exactly one digit 0-4; XATOI would silently map
* non-numeric input (e.g. -loc=abc or -loc=) to locality 0. */
if (argv[i][5] < '0' || argv[i][5] > '4' || argv[i][6] != '\0') {
printf("Locality is out of range (0-4)\n");
usage();
goto exit_badargs;
}
locality = argv[i][5] - '0';
}
else if (argv[i][0] >= '0' && argv[i][0] <= '9') {
pcrIndex = XATOI(argv[i]);
if (pcrIndex < 0 || pcrIndex > 23) {
printf("PCR index is out of range (0-23)\n");
usage();
goto exit_badargs;
}
}
else {
printf("Incorrect arguments\n");
usage();
goto exit_badargs;
}
}
else if (argc == 1) {
pcrIndex = TPM2_TEST_PCR;
}
else {
printf("Incorrect arguments\n");
usage();
goto exit_badargs;
}

printf("Demo how to reset a PCR (clear PCR value)\n");
rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
Expand All @@ -88,6 +103,18 @@ int TPM2_PCR_Reset_Test(void* userCtx, int argc, char *argv[])
}
printf("wolfTPM2_Init: success\n");

if (locality >= 0) {
printf("Switching to locality %d...\n", locality);
rc = wolfTPM2_SetLocality(&dev, locality);
if (rc != TPM_RC_SUCCESS) {
printf("wolfTPM2_SetLocality(%d) failed 0x%x: %s\n", locality, rc,
TPM2_GetRCString(rc));
goto exit;
}
printf("wolfTPM2_SetLocality: now at locality %d\n", locality);
localitySwitched = 1;
}

/* Prepare PCR Reset command */
XMEMSET(&cmdIn.pcrReset, 0, sizeof(cmdIn.pcrReset));
cmdIn.pcrReset.pcrHandle = pcrIndex;
Expand Down Expand Up @@ -116,6 +143,13 @@ int TPM2_PCR_Reset_Test(void* userCtx, int argc, char *argv[])

exit:
Comment thread
dgarske marked this conversation as resolved.

/* Return to the default locality so a non-zero one is not left active
* (which would block the next TPM startup on TPMs that do not preempt).
* Only when a switch actually succeeded - never on a failed Init. */
if (localitySwitched) {
(void)wolfTPM2_SetLocality(&dev, 0);
}

wolfTPM2_Cleanup(&dev);

exit_badargs:
Expand Down
16 changes: 16 additions & 0 deletions examples/run_examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,22 @@ echo -e "Endorsement Key (EK) and Certificate"
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "get_ek_certs failed! $RESULT" && exit 1

# PCR reset locality (-loc): smoke-exercise wolfTPM2_SetLocality. Reset PCR 16
# at locality 0 (universally resettable, a no-op switch). This runs against
# whichever backend is present (ibmswtpm2, fwTPM, ...) so it does not assert the
# backend-specific per-PCR map - that rigor lives in tests/fwtpm_check.sh.
echo -e "PCR reset locality (-loc)"
LOC_OUT=$(./examples/pcr/reset 16 -loc=0 2>&1)
echo "$LOC_OUT" >> $TPMPWD/run.out
if echo "$LOC_OUT" | grep -q "TPM2_PCR_Reset success"; then
Comment thread
dgarske marked this conversation as resolved.
: # -loc supported and works
elif echo "$LOC_OUT" | grep -qiE "not compiled in|NOT_COMPILED_IN"; then
# kernel (/dev/tpm0) and Windows TBS own the locality; TPM2_GetRCString
# renders NOT_COMPILED_IN as "Feature not compiled in" under wolfCrypt.
echo -e " -loc not supported by this backend, skipping"
else
echo -e "pcr reset -loc failed!" && exit 1
fi

rm -f keyblob.bin

Expand Down
10 changes: 6 additions & 4 deletions examples/spdm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@ effect. The reset pin must be connected and controllable by the host.
to a host-controllable GPIO. Without reset pin control, SPDM mode changes
cannot be applied and recovery from SPDM-only mode is not possible.

### Raspberry Pi Example (GPIO 4)
The reset line is board specific. On a Raspberry Pi, Nuvoton uses GPIO4 and the
ST33KTPM uses GPIO24 (pin 18); confirm your wiring before toggling.

```bash
# Assert reset low, wait, release high, wait for TPM startup
# Assert reset low, release high, wait for TPM startup (Nuvoton GPIO4 shown)
gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2
# ST33: use line 24 instead of 4
```

Other platforms will use their own GPIO control mechanism. The key requirement
is toggling the TPM reset line (active low) with sufficient hold time.
wolfTPM can also drive this from code: build with `--enable-hal-reset` and call
`TPM2_IoCb_Reset()` (default line: ST33 GPIO24, Nuvoton GPIO4). See `hal/README.md`.

## Automated Test Suite

Expand Down
7 changes: 7 additions & 0 deletions hal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
* `WOLFTPM_CHECK_WAIT_STATE`: Enables check of the wait state during a SPI transaction. Most TPM 2.0 chips require this and typically only require 0-2 wait cycles depending on the command. Only the Infineon TPM's guarantee no wait states.
* `WOLFTPM_ADV_IO`: Enables advanced IO callback mode that includes TIS register and read/write flag. This is requires for I2C, but can be used with SPI also.
* `WOLFTPM_DEBUG_IO`: Enable logging of the IO (if using the example HAL).
* `WOLFTPM_HAL_RESET`: Optional TPM hardware reset (nRST) control in the example HAL (`--enable-hal-reset`). On Linux, `TPM2_IoCb_Reset(&dev->ctx, userCtx)` pulses nRST (active low) via the GPIO char device (raw GPIO v2 uAPI, no libgpiod).

## TPM reset (nRST) HAL macros (when `WOLFTPM_HAL_RESET` is set)

* `WOLFTPM_RESET_GPIOCHIP`: GPIO char device. Default: `/dev/gpiochip0`
* `WOLFTPM_RESET_LINE`: GPIO line wired to nRST. Default: ST33 = `24` (GPIO24, Pi pin 18), Nuvoton = `4` (GPIO4). Also settable via `--enable-hal-reset=<line>`.
* `WOLFTPM_RESET_HOLD_US` / `WOLFTPM_RESET_SETTLE_US`: reset hold / post-reset settle time (us). Defaults: `300000` / `1000000`.

## Additional Compiler macros

Expand Down
23 changes: 23 additions & 0 deletions hal/tpm_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,29 @@ int TPM2_IoCb(TPM2_CTX* ctx, const BYTE* txBuf, BYTE* rxBuf,
}

#endif /* WOLFTPM_ADV_IO */

#ifdef WOLFTPM_HAL_RESET
/* Pulse the TPM hardware reset (nRST) line to reset the TPM. Dispatches to the
* platform implementation. Returns TPM_RC_SUCCESS on success. */
int TPM2_IoCb_Reset(TPM2_CTX* ctx, void* userCtx)
{
int ret;
#if defined(__linux__)
Comment thread
dgarske marked this conversation as resolved.
ret = TPM2_IoCb_Linux_Reset(ctx, userCtx);
#else
/* No reset HAL for this OS - return NOT_COMPILED_IN so callers can tell it
* apart from a genuine reset failure (TPM_RC_FAILURE) on a supported OS. */
(void)ctx;
(void)userCtx;
ret = NOT_COMPILED_IN;
#ifdef DEBUG_WOLFTPM
printf("TPM reset HAL not implemented for this platform\n");
#endif
#endif
return ret;
}
#endif /* WOLFTPM_HAL_RESET */

#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */

/******************************************************************************/
Expand Down
9 changes: 9 additions & 0 deletions hal/tpm_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ WOLFTPM_LOCAL int TPM2_IoCb_FwTPM(TPM2_CTX* ctx, int isRead, word32 addr,
byte* buf, word16 size, void* userCtx);
#endif

#ifdef WOLFTPM_HAL_RESET
/* Optional TPM hardware reset (nRST) control. Pulses the reset line to reset
* the TPM. Enable with --enable-hal-reset (-DWOLFTPM_HAL_RESET). */
WOLFTPM_API int TPM2_IoCb_Reset(TPM2_CTX* ctx, void* userCtx);
#if defined(__linux__)
WOLFTPM_LOCAL int TPM2_IoCb_Linux_Reset(TPM2_CTX* ctx, void* userCtx);
#endif
#endif

#endif /* WOLFTPM_EXAMPLE_HAL */
#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */

Expand Down
Loading
Loading