Skip to content

Commit b4b4509

Browse files
authored
Merge pull request #460 from aidangarske/fix-issue-457
Improve error logging when wolfTPM2_Init fails
2 parents bdd6277 + 0aefc3b commit b4b4509

14 files changed

Lines changed: 262 additions & 23 deletions

File tree

.github/workflows/make-test-swtpm.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ jobs:
108108
wolftpm_config: --enable-advio
109109
needs_swtpm: false
110110

111+
# Autodetect (default configure, /dev/tpm0 + SPI dual support)
112+
- name: autodetect
113+
wolftpm_config: ""
114+
needs_swtpm: false
115+
116+
# Autodetect with debug
117+
- name: autodetect-debug
118+
wolftpm_config: --enable-debug
119+
needs_swtpm: false
120+
111121
# Clang ASAN
112122
- name: clang-asan
113123
wolftpm_cflags: "-fsanitize=address -fno-omit-frame-pointer -g"

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Portable TPM 2.0 project designed for embedded use.
99
* Wrappers provided to simplify Key Generation/Loading, RSA encrypt/decrypt, ECC sign/verify, ECDH, NV, Hashing/HACM, AES, Sealing/Unsealing, Attestation, PCR Extend/Quote and Secure Root of Trust.
1010
* Testing done using TPM 2.0 modules from STMicro ST33 (SPI/I2C), Infineon OPTIGA SLB9670/SLB9672/SLB9673, Microchip ATTPM20, Nations Tech Z32H330TC/NS350 and Nuvoton NPCT650/NPCT750.
1111
* wolfTPM uses the TPM Interface Specification (TIS) to communicate either over SPI, or using a memory mapped I/O range.
12+
* On Linux, wolfTPM auto-detects between the kernel TPM driver (`/dev/tpmX`) and direct SPI access at runtime — a simple `./configure && make` works with either interface.
1213
* wolfTPM can also use the Linux TPM kernel interface (`/dev/tpmX`) to talk with any physical TPM on SPI, I2C and even LPC bus.
1314
* Platform support for Raspberry Pi (Linux), MMIO, STM32 with CubeMX, Atmel ASF, Xilinx, QNX Infineon TriCore and Barebox.
1415
* The design allows for easy portability to different platforms:
@@ -192,12 +193,16 @@ make install
192193
--enable-firmware Enable firmware upgrade support for Infineon SLB9672/SLB9673 and ST ST33 (default: disabled) - WOLFTPM_FIRMWARE_UPGRADE
193194
194195
--enable-autodetect Enable Runtime Module Detection (default: enable - when no module specified) - WOLFTPM_AUTODETECT
196+
On Linux this also auto-detects /dev/tpmrm0 or /dev/tpm0 at runtime,
197+
falling back to SPI if the kernel driver is not available.
195198
--enable-infineon Enable Infineon SLB9670/SLB9672/SLB9673 TPM Support (default: disabled) - WOLFTPM_SLB9670 / WOLFTPM_SLB9672
196199
--enable-st Enable ST ST33 Support (default: disabled) - WOLFTPM_ST33
197200
--enable-microchip Enable Microchip ATTPM20 Support (default: disabled) - WOLFTPM_MICROCHIP
198201
--enable-nuvoton Enable Nuvoton NPCT65x/NPCT75x Support (default: disabled) - WOLFTPM_NUVOTON
199202
200203
--enable-devtpm Enable using Linux kernel driver for /dev/tpmX (default: disabled) - WOLFTPM_LINUX_DEV
204+
Note: With autodetect (default) this is no longer required on Linux;
205+
the kernel driver is tried automatically before SPI.
201206
--enable-swtpm Enable using SWTPM TCP protocol. For use with simulator. (default: disabled) - WOLFTPM_SWTPM
202207
--enable-winapi Use Windows TBS API. (default: disabled) - WOLFTPM_WINAPI
203208
@@ -283,7 +288,15 @@ idf.py build
283288

284289
### Building for "/dev/tpmX"
285290

286-
The `--enable-devtpm` or `WOLFTPM_LINUX_DEV` build option allows you to use the Linux supplied TPM (TIS) driver.
291+
**Auto-detection (recommended):** On Linux, a default `./configure && make` will automatically try `/dev/tpmrm0` then `/dev/tpm0` at runtime. If the kernel driver is available it will be used; otherwise wolfTPM falls back to direct SPI access. No special configure options are needed.
292+
293+
```bash
294+
./autogen.sh
295+
./configure
296+
make
297+
```
298+
299+
Previously, using the kernel TPM driver required the `--enable-devtpm` flag. This is no longer necessary with autodetect (enabled by default). You can still use `--enable-devtpm` to force kernel-driver-only mode, which disables SPI fallback.
287300

288301
To specify a different `/dev/tpmX` device use `CFLAGS="-DTPM2_LINUX_DEV=/dev/tpm1"`
289302

examples/bench/bench.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,10 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
262262

263263
/* Init the TPM2 device */
264264
rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
265-
if (rc != 0) return rc;
265+
if (rc != 0) {
266+
printf("wolfTPM2_Init failed\n");
267+
return rc;
268+
}
266269

267270
/* See if primary storage key already exists */
268271
rc = getPrimaryStoragekey(&dev, &storageKey, TPM_ALG_RSA);

examples/pkcs7/pkcs7.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,10 @@ int TPM2_PKCS7_ExampleArgs(void* userCtx, int argc, char *argv[])
417417

418418
/* Init the TPM2 device */
419419
rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
420-
if (rc != 0) return rc;
420+
if (rc != 0) {
421+
printf("wolfTPM2_Init failed\n");
422+
return rc;
423+
}
421424

422425
/* Setup the wolf crypto device callback */
423426
XMEMSET(&tpmCtx, 0, sizeof(tpmCtx));

examples/wrap/caps.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ int TPM2_Wrapper_CapsArgs(void* userCtx, int argc, char *argv[])
106106

107107
/* Init the TPM2 device */
108108
rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
109-
if (rc != 0) return rc;
109+
if (rc != 0) {
110+
printf("wolfTPM2_Init failed\n");
111+
return rc;
112+
}
110113

111114
rc = wolfTPM2_GetCapabilities(&dev, &caps);
112115
if (rc != 0) goto exit;

examples/wrap/wrap_test.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[])
168168

169169
/* Init the TPM2 device */
170170
rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
171-
if (rc != 0) return rc;
171+
if (rc != 0) {
172+
printf("wolfTPM2_Init failed\n");
173+
return rc;
174+
}
172175

173176
#ifdef WOLFTPM_CRYPTOCB
174177
/* Setup the wolf crypto device callback */

hal/tpm_io_linux.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@
6363
#endif
6464
#include <fcntl.h>
6565
#include <unistd.h>
66+
#include <errno.h>
6667

6768
#ifdef WOLFTPM_I2C
6869
/* I2C - (Only tested with SLB9673 and ST33 I2C) */
6970
#define TPM2_I2C_ADDR 0x2e
7071
#define TPM2_I2C_DEV "/dev/i2c-1"
7172
#define TPM2_I2C_HZ 400000 /* 400kHz */
73+
static int i2cOpenFailed = 0;
7274
#else
7375
/* SPI */
7476
#ifndef TPM2_SPI_DEV_CS
@@ -97,8 +99,10 @@
9799
static char TPM2_SPI_DEV[] = TPM2_SPI_DEV_PATH "0";
98100
#define MAX_SPI_DEV_CS '4'
99101
static int foundSpiDev = 0;
102+
static int spiDevNotFound = 0;
100103
#else
101104
#define TPM2_SPI_DEV TPM2_SPI_DEV_PATH TPM2_SPI_DEV_CS
105+
static int spiOpenFailed = 0;
102106
#endif
103107
#endif
104108
#endif
@@ -190,6 +194,20 @@
190194

191195
close(i2cDev);
192196
}
197+
else if (!i2cOpenFailed) {
198+
i2cOpenFailed = 1;
199+
if (errno == EACCES) {
200+
printf("Permission denied on %s\n"
201+
"Use sudo or add appropriate group to user.\n",
202+
TPM2_I2C_DEV);
203+
}
204+
#ifdef DEBUG_WOLFTPM
205+
else {
206+
printf("Failed to open I2C device %s (errno %d)\n",
207+
TPM2_I2C_DEV, errno);
208+
}
209+
#endif
210+
}
193211

194212
(void)ctx;
195213
(void)userCtx;
@@ -198,6 +216,39 @@
198216
}
199217

200218
#else
219+
/* Called when SPI device cannot be opened or no TPM found on SPI bus.
220+
* Checks if the Linux kernel TPM driver is available and suggests
221+
* alternatives. */
222+
static void spiOpenFailedMessage(void)
223+
{
224+
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
225+
/* Autodetect already tried /dev/tpm0; SPI also failed */
226+
#ifdef DEBUG_WOLFTPM
227+
printf("Neither /dev/tpm0 nor SPI bus produced a TPM response.\n"
228+
"Ensure a TPM is connected and the kernel driver or spidev "
229+
"is enabled.\n");
230+
#endif
231+
#else
232+
if (access("/dev/tpm0", F_OK) == 0 ||
233+
access("/dev/tpmrm0", F_OK) == 0) {
234+
printf("TPM kernel driver detected (/dev/tpm0).\n"
235+
"Either build wolfTPM with ./configure --enable-devtpm\n"
236+
"or disable the kernel driver by commenting out the TPM\n"
237+
"overlay in /boot/config.txt or /boot/firmware/config.txt\n"
238+
"and enable spidev to use direct SPI access.\n");
239+
}
240+
#ifdef DEBUG_WOLFTPM
241+
else {
242+
printf("If using Linux kernel TPM driver (/dev/tpm0), "
243+
"build with --enable-devtpm.\n"
244+
"To use SPI directly, make sure /dev/spidev is available "
245+
"and the TPM\nkernel overlay is disabled in /boot/config.txt "
246+
"or /boot/firmware/config.txt.\n");
247+
}
248+
#endif
249+
#endif /* WOLFTPM_LINUX_DEV_AUTODETECT */
250+
}
251+
201252
/* Use Linux SPI synchronous access */
202253
int TPM2_IoCb_Linux_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
203254
word16 xferSz, void* userCtx)
@@ -308,6 +359,23 @@
308359
else {
309360
/* Failed to open device */
310361
ret = TPM_RC_FAILURE;
362+
#ifndef WOLFTPM_AUTODETECT
363+
if (!spiOpenFailed) {
364+
spiOpenFailed = 1;
365+
if (errno == EACCES) {
366+
printf("Permission denied on %s\n"
367+
"Use sudo or check device permissions.\n",
368+
TPM2_SPI_DEV);
369+
}
370+
else {
371+
#ifdef DEBUG_WOLFTPM
372+
printf("Failed to open SPI device %s (errno %d)\n",
373+
TPM2_SPI_DEV, errno);
374+
#endif
375+
spiOpenFailedMessage();
376+
}
377+
}
378+
#endif
311379
}
312380

313381
#ifdef WOLFTPM_AUTODETECT
@@ -326,6 +394,14 @@
326394
TPM2_SPI_DEV[devLen-1]++;
327395
goto tryagain;
328396
}
397+
if (!spiDevNotFound) {
398+
spiDevNotFound = 1;
399+
#ifdef DEBUG_WOLFTPM
400+
printf("TPM not found on SPI bus %s[0-%c]\n",
401+
TPM2_SPI_DEV_PATH, MAX_SPI_DEV_CS);
402+
#endif
403+
spiOpenFailedMessage();
404+
}
329405
}
330406
}
331407
#endif

src/include.am

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,8 @@ src_libwolftpm_la_SOURCES = \
1111
src/tpm2_wrap.c \
1212
src/tpm2_asn.c \
1313
src/tpm2_param_enc.c \
14-
src/tpm2_cryptocb.c
15-
16-
if BUILD_DEVTPM
17-
src_libwolftpm_la_SOURCES += src/tpm2_linux.c
18-
endif
14+
src/tpm2_cryptocb.c \
15+
src/tpm2_linux.c
1916
if BUILD_SWTPM
2017
src_libwolftpm_la_SOURCES += src/tpm2_swtpm.c
2118
endif

src/tpm2.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ static THREAD_LS_T TPM2_CTX* gActiveTPM;
6060
#ifdef WOLFTPM_LINUX_DEV
6161
#define INTERNAL_SEND_COMMAND TPM2_LINUX_SendCommand
6262
#define TPM2_INTERNAL_CLEANUP(ctx)
63+
#elif defined(WOLFTPM_LINUX_DEV_AUTODETECT)
64+
#define INTERNAL_SEND_COMMAND TPM2_LINUX_AUTODETECT_SendCommand
65+
#define TPM2_INTERNAL_CLEANUP(ctx)
6366
#elif defined(WOLFTPM_SWTPM)
6467
#define INTERNAL_SEND_COMMAND TPM2_SWTPM_SendCommand
6568
#define TPM2_INTERNAL_CLEANUP(ctx)
@@ -647,6 +650,13 @@ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
647650
if (ioCb != NULL || userCtx != NULL) {
648651
return BAD_FUNC_ARG;
649652
}
653+
#elif defined(WOLFTPM_LINUX_DEV_AUTODETECT)
654+
/* Accept IO callback for SPI fallback path */
655+
if (ioCb != NULL) {
656+
rc = TPM2_SetHalIoCb(ctx, ioCb, userCtx);
657+
if (rc != TPM_RC_SUCCESS)
658+
return rc;
659+
}
650660
#else
651661
#ifdef WOLFTPM_MMIO
652662
if (ioCb == NULL)
@@ -658,14 +668,18 @@ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx,
658668
return rc;
659669
#endif
660670

661-
#ifdef WOLFTPM_LINUX_DEV
671+
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_LINUX_DEV_AUTODETECT)
662672
ctx->fd = -1;
663673
#endif
664674

665675
/* Set the active TPM global */
666676
TPM2_SetActiveCtx(ctx);
667677

668-
if (timeoutTries > 0) {
678+
if (timeoutTries > 0
679+
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
680+
&& ctx->ioCb != NULL /* autodetect: skip if no IO callback */
681+
#endif
682+
) {
669683
/* Perform chip startup and assign locality */
670684
rc = TPM2_ChipStartup(ctx, timeoutTries);
671685
}
@@ -729,7 +743,8 @@ TPM_RC TPM2_Cleanup(TPM2_CTX* ctx)
729743
}
730744
#endif /* !WOLFTPM2_NO_WOLFCRYPT */
731745

732-
#if defined(WOLFTPM_LINUX_DEV) && !defined(__UBOOT__)
746+
#if (defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_LINUX_DEV_AUTODETECT)) \
747+
&& !defined(__UBOOT__)
733748
if (ctx->fd >= 0)
734749
close(ctx->fd);
735750
#endif

src/tpm2_linux.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
#include <wolftpm/tpm2_types.h>
2727

28-
#ifdef WOLFTPM_LINUX_DEV
28+
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_LINUX_DEV_AUTODETECT)
2929
#include <wolftpm/tpm2_linux.h>
3030
#include <wolftpm/tpm2_packet.h>
3131

@@ -194,4 +194,46 @@ int TPM2_LINUX_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
194194
return rc;
195195
}
196196
#endif /* __UBOOT__ __linux__ */
197-
#endif /* WOLFTPM_LINUX_DEV */
197+
198+
#ifdef WOLFTPM_LINUX_DEV_AUTODETECT
199+
#include <wolftpm/tpm2_tis.h>
200+
201+
int TPM2_LINUX_TryOpen(TPM2_CTX* ctx)
202+
{
203+
/* Try resource manager first (kernel 4.12+), then raw device */
204+
ctx->fd = open("/dev/tpmrm0", O_RDWR | O_NONBLOCK);
205+
if (ctx->fd >= 0) {
206+
#ifdef DEBUG_WOLFTPM
207+
printf("Opened /dev/tpmrm0\n");
208+
#endif
209+
return TPM_RC_SUCCESS;
210+
}
211+
212+
ctx->fd = open("/dev/tpm0", O_RDWR | O_NONBLOCK);
213+
if (ctx->fd >= 0) {
214+
#ifdef DEBUG_WOLFTPM
215+
printf("Opened /dev/tpm0\n");
216+
#endif
217+
return TPM_RC_SUCCESS;
218+
}
219+
220+
/* Distinguish "not available" from "permission denied" */
221+
if (errno == EACCES) {
222+
printf("Permission denied on /dev/tpm0\n"
223+
"Use sudo or add tss group to user.\n");
224+
return TPM_RC_FAILURE;
225+
}
226+
227+
/* ENOENT or other: device not present, caller should try SPI */
228+
return TPM_RC_INITIALIZE; /* sentinel: "not found, try next" */
229+
}
230+
231+
int TPM2_LINUX_AUTODETECT_SendCommand(TPM2_CTX* ctx, TPM2_Packet* packet)
232+
{
233+
if (ctx->fd >= 0)
234+
return TPM2_LINUX_SendCommand(ctx, packet);
235+
return TPM2_TIS_SendCommand(ctx, packet);
236+
}
237+
#endif /* WOLFTPM_LINUX_DEV_AUTODETECT */
238+
239+
#endif /* WOLFTPM_LINUX_DEV || WOLFTPM_LINUX_DEV_AUTODETECT */

0 commit comments

Comments
 (0)