Skip to content

Add new Firmware TPM (fwTPM)#474

Open
dgarske wants to merge 12 commits intowolfSSL:masterfrom
dgarske:fwtpm
Open

Add new Firmware TPM (fwTPM)#474
dgarske wants to merge 12 commits intowolfSSL:masterfrom
dgarske:fwtpm

Conversation

@dgarske
Copy link
Copy Markdown
Contributor

@dgarske dgarske commented Mar 21, 2026

Summary

  • Add firmware TPM 2.0 server (fwTPM) implementing TPM 2.0 spec v1.38 (105/113 commands, 93% coverage)
  • Spec-compliant primary key derivation: deterministic RSA (iterative KDFa prime generation), ECC (KDFa scalar, Q=d*G), KEYEDHASH/SYMCIPHER keys — same seed + template always produces the same key
  • ChangePPS / ChangeEPS hierarchy commands with seed regeneration and cache flush
  • NV storage with TLV journal format (flash-friendly, append-only)
  • Socket (mssim) and TIS/SHM transports for desktop, UART transport for embedded
  • STM32 Cortex-M33 bare-metal port with TrustZone (CMSE) support
  • Shared crypto refactoring: extract KDFa/KDFe, AES-CFB, HMAC/Hash to tpm2_crypto.c
  • Bounds-checked TPM2_Packet_ParseU16Buf variant for safer response parsing
  • Auth validation: reject oversized auth values instead of silent truncation
  • SIGTERM/SIGINT signal handler for graceful NV save on server kill

fwTPM Server

Core TPM 2.0 command processing in src/fwtpm/:

  • fwtpm_command.c — 105 command handlers with full auth, sessions, parameter encryption
  • fwtpm_nv.c — TLV journal NV storage (file-based default, HAL-abstracted for flash)
  • fwtpm_io.c — Socket transport (mssim + swtpm protocol auto-detection)
  • fwtpm_tis.c / fwtpm_tis_shm.c — TIS register interface via POSIX shared memory
  • fwtpm_crypto.c — Key generation, sign/verify, seed encrypt/decrypt helpers
  • Clock HAL with NV-persisted clockOffset

Build: ./configure --enable-fwtpm && make

Example: wolfSSL/wolftpm-examples#1

Primary Key Derivation (TPM 2.0 Part 1 Section 26)

  • RSA: iterative KDFa prime generation with labels "RSA p" / "RSA q"
  • ECC: KDFa scalar derivation, public point Q = d*G
  • KEYEDHASH/SYMCIPHER: KDFa with algorithm-specific labels
  • hashUnique = H(sensitiveCreate.data || unique) per Section 26.1
  • Primary cache retained as performance optimization, no longer required for correctness

UART Transport (--enable-swtpm=uart)

New transport option for wolfTPM client library to communicate with embedded fwTPM over serial:

  • ./configure --enable-swtpm=uart — uses termios serial I/O instead of TCP sockets
  • TPM2_SWTPM_HOST env var selects serial device at runtime
  • Same mssim protocol as socket transport (compatible with all wolfTPM examples)

Testing

  • 311 tpm2-tools compatibility tests (scripts/tpm2_tools_test.sh)
  • Full wolfTPM example suite (examples/run_examples.sh)
  • libFuzzer harness with corpus generator (tests/fuzz/)
  • m33mu Cortex-M33 emulator CI test (scripts/fwtpm_emu_test.sh)
  • ASan / UBSan clean
  • 20 CI matrix configurations (pedantic gcc/clang -Werror, sanitizers, feature-disable variants)

wolfSSL-Fenrir-bot

This comment was marked as resolved.

@dgarske dgarske force-pushed the fwtpm branch 3 times, most recently from 9c0208f to eae465e Compare March 21, 2026 23:51
@dgarske dgarske changed the title Add fwTPM firmware TPM 2.0 server with STM32 port Add fwTPM firmware TPM 2.0 server Mar 21, 2026
@dgarske dgarske changed the title Add fwTPM firmware TPM 2.0 server Add new Firmware TPM (fwTPM) Mar 22, 2026
@dgarske dgarske force-pushed the fwtpm branch 2 times, most recently from b186ecc to f529484 Compare March 23, 2026 21:28
@dgarske dgarske assigned wolfSSL-Bot and unassigned dgarske and aidangarske Mar 24, 2026
@dgarske dgarske assigned dgarske and unassigned wolfSSL-Bot Mar 25, 2026
wolfSSL-Fenrir-bot

This comment was marked as resolved.

wolfSSL-Fenrir-bot

This comment was marked as resolved.

This comment was marked as resolved.

@aidangarske aidangarske requested a review from danielinux March 25, 2026 20:51
Comment thread src/fwtpm/fwtpm_nv.c Outdated
Comment thread src/fwtpm/fwtpm_nv.c
Comment thread src/fwtpm/fwtpm_command.c Outdated
Copilot AI review requested due to automatic review settings April 3, 2026 17:42

This comment was marked as resolved.

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 13, 2026 21:56

This comment was marked as resolved.

aidangarske

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 14, 2026 21:46

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings April 15, 2026 16:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 69 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tpm2_packet.c Outdated
Comment thread src/fwtpm/fwtpm_tis.c Outdated
Comment thread src/fwtpm/fwtpm_tis_shm.c
Comment thread src/tpm2_packet.c
Comment thread src/tpm2_packet.c
Comment thread src/tpm2_packet.c
Comment thread src/tpm2_packet.c
Comment thread tests/unit_tests.c
Comment thread CMakeLists.txt
Copy link
Copy Markdown

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #474

Scan targets checked: wolftpm-bugs, wolftpm-consttime, wolftpm-defaults, wolftpm-mutation, wolftpm-proptest, wolftpm-src, wolftpm-zeroize

Findings: 4
4 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread examples/native/native_test.c
Comment thread src/tpm2_swtpm.c
Comment thread src/tpm2_crypto.c
Comment thread src/fwtpm/fwtpm_crypto.c
Copilot AI review requested due to automatic review settings April 15, 2026 20:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 71 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/tpm2_swtpm.c:199

  • For UART mode, read() can legally return 0 due to VMIN=0/VTIME>0 timeout (not EOF). Treating wrc==0 as EOF will break long-running fwTPM operations over UART (e.g., RSA keygen) and prevents the cumulative timeout logic below from ever triggering. Fix by handling wrc==0 differently under WOLFTPM_SWTPM_UART (e.g., continue polling until the cumulative timeout elapses), while keeping the EOF behavior for sockets.
    while (bytes_remaining > 0) {
        wrc = read(ctx->tcpCtx.fd, ptr, bytes_remaining);
        if (wrc < 0) {
            /* Retry on EINTR; treat EAGAIN/EWOULDBLOCK as transient too. */
            if (errno == EINTR
                #ifdef EAGAIN
                    || errno == EAGAIN
                #endif
                #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
                    || errno == EWOULDBLOCK
                #endif
            ) {
                continue;
            }
            #ifdef DEBUG_WOLFTPM
            printf("Failed to read from TPM socket %d, got errno %d"
                   " = %s\n", ctx->tcpCtx.fd, errno, strerror(errno));
            #endif
            rc = TPM_RC_FAILURE;
            break;
        }
        if (wrc == 0) {
            #ifdef DEBUG_WOLFTPM
            printf("Failed to read from TPM socket: EOF\n");
            #endif
            rc = TPM_RC_FAILURE;
            break;
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tpm2_crypto.c
Comment thread tests/include.am
Comment thread tests/unit_tests.c Outdated
Copilot AI review requested due to automatic review settings April 16, 2026 00:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 53 out of 71 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

src/tpm2_swtpm.c:199

  • In UART mode, termios is configured with VMIN=0 and VTIME>0, where read() returning 0 indicates a timeout (no bytes yet), not EOF. Treating wrc==0 as EOF will cause spurious failures for long-running TPM operations. For WOLFTPM_SWTPM_UART, handle wrc==0 as a transient timeout and continue waiting until the cumulative timeout is reached (the CLOCK_MONOTONIC block you added is a good place to enforce the overall limit). Keep the EOF behavior for socket mode.
        if (wrc == 0) {
            #ifdef DEBUG_WOLFTPM
            printf("Failed to read from TPM socket: EOF\n");
            #endif
            rc = TPM_RC_FAILURE;
            break;
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tpm2_wrap.c
Comment on lines 1761 to 1769
session->auth.size = authDigestSz + handle->auth.size;
XMEMCPY(&session->auth.buffer[authDigestSz], handle->auth.buffer,
handle->auth.size);
if (handle->name.size > sizeof(session->name.name)) {
return BUFFER_E;
}
session->name.size = handle->name.size;
if (session->name.size > sizeof(session->name.name)) {
session->name.size = sizeof(session->name.name); /* truncate */
}
XMEMCPY(session->name.name, handle->name.name, session->name.size);
return TPM_RC_SUCCESS;
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Truncating handle->name.size here can leave the session in a state where session->name no longer matches the real object name. That can break authorization/HMAC computations in later command flows and can also hide an upstream size/encoding error. Prefer keeping the previous behavior: validate handle->name.size against sizeof(session->name.name) and return BUFFER_E rather than truncating.

Copilot uses AI. Check for mistakes.
Comment thread src/fwtpm/fwtpm_tis.c
Comment on lines +329 to +339
/* Clamp len for scalar registers (max 4 bytes) and zero-fill
* to prevent stale data in reg_data from being read back */
if (len > 4) {
len = 4;
}
XMEMSET(regs->reg_data, 0, len);
/* Pack value into reg_data (little-endian, matching TIS spec) */
if (len >= 1) regs->reg_data[0] = (BYTE)(val);
if (len >= 2) regs->reg_data[1] = (BYTE)(val >> 8);
if (len >= 3) regs->reg_data[2] = (BYTE)(val >> 16);
if (len >= 4) regs->reg_data[3] = (BYTE)(val >> 24);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This read path only zeroes len bytes (clamped to 4), but the client-side HAL copies the originally requested size bytes from reg_data and does not know about the server-side clamp. That can leak stale shared-memory contents beyond the first 4 bytes. To prevent data disclosure, zero the entire regs->reg_data buffer (or at least regs->reg_len bytes as requested) before writing the scalar register bytes.

Copilot uses AI. Check for mistakes.
Comment thread scripts/fwtpm_emu_test.sh Outdated
# Show UART output (filter emulator noise)
echo ""
echo "--- fwTPM output ---"
grep -E "^===|^fwTPM|^ |^Running|^ Startup|^ SelfTest|^ GetRandom|^ GetCapability|^ Random|^All self|^SELF-TEST" "$LOG"
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script runs with set -e, so if the grep pattern matches nothing (e.g., on early boot failure or different output), grep exits 1 and the whole script aborts before the intended result checks and log tail. Consider appending || true (or temporarily disabling set -e around this grep) so the script can still report failures and show diagnostics consistently.

Suggested change
grep -E "^===|^fwTPM|^ |^Running|^ Startup|^ SelfTest|^ GetRandom|^ GetCapability|^ Random|^All self|^SELF-TEST" "$LOG"
grep -E "^===|^fwTPM|^ |^Running|^ Startup|^ SelfTest|^ GetRandom|^ GetCapability|^ Random|^All self|^SELF-TEST" "$LOG" || true

Copilot uses AI. Check for mistakes.
Comment thread hal/tpm_io_fwtpm.c Outdated
}
#ifndef O_CLOEXEC
/* Fallback for platforms without O_CLOEXEC */
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fcntl(fd, F_SETFD, FD_CLOEXEC) overwrites existing FD flags instead of preserving them. Use F_GETFD and OR-in FD_CLOEXEC (as done elsewhere in the PR) so you don't accidentally clear other descriptor flags.

Suggested change
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
{
int fdFlags = fcntl(fd, F_GETFD);
if (fdFlags >= 0) {
(void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC);
}
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants