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
47 changes: 26 additions & 21 deletions examples/firmware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Currently wolfTPM supports firmware update capability for:
- Infineon SLB9672 (SPI) and SLB9673 (I2C) TPM 2.0 modules. Infineon has open sourced their firmware update.
- STMicroelectronics ST33KTPM TPM 2.0 modules. Support includes both Generation 1 firmware versions (< 512, without LMS signature) and Generation 2 firmware versions (>= 512, with LMS signature requirement).
- STMicroelectronics ST33KTPM TPM 2.0 modules. Support covers generation 1 firmware (RSA signed manifest), generation 9 firmware below 512 (ECDSA signed manifest) and generation 9 firmware at 512 and above (LMS signature requirement).

## Infineon Firmware

Expand Down Expand Up @@ -117,15 +117,19 @@ KeyGroupId 0x7, FwCounter 1253 (254 same)

ST33KTPM firmware update automatically detects the required format based on TPM firmware version:

- **Legacy firmware (< 512, e.g., 9.257)**: Non-LMS format
- Manifest size: 177 bytes
- Generation 1 firmware (ECC-only)
The manifest (blob0) is a 33 byte fixed header followed by the firmware digest and the signature over it, so its size follows the algorithms that generation signs with:

- **Modern firmware (>= 512, e.g., 9.512)**: LMS format
- **Generation 1 (major version 1, e.g., 1.257 or 1.771)**: Non-LMS format
- Manifest size: 321 bytes (SHA-256 digest, RSAPSS-2048 signature)
- Always non-LMS, no matter how high the minor version goes

- **Generation 9 below 512 (e.g., 9.257)**: Non-LMS format
- Manifest size: 177 bytes (SHA-384 digest, ECDSA P-384 signature)

- **Generation 9 at 512 and above (e.g., 9.512)**: LMS format
- Manifest size: 2697 bytes (includes embedded LMS signature)
- Generation 2 firmware (LMS mandatory)

The firmware version is automatically detected from `fwVerMinor` in TPM capabilities. The correct manifest size is determined automatically - no manual format selection is needed.
The LMS requirement is a generation 9 rule, so both `fwVerMajor` and `fwVerMinor` from TPM capabilities are consulted. The example confirms its choice against the file itself: everything after blob0 is a chain of `[type][length]` records that ends exactly at end of file, and only the correct manifest size lands on the final byte. No manual format selection is needed.

### Updating the firmware

Expand All @@ -145,9 +149,10 @@ Policy options (caller-supplied authorization):
--policyor provision+satisfy a PolicyOR (multi-branch)
--sha256|--sha384|--sha512 policy hash (default SHA-256)

Firmware format is auto-detected from TPM firmware version:
- Firmware < 512: Non-LMS format (177 byte manifest)
- Firmware >= 512: LMS format (2697 byte manifest with embedded signature)
Firmware format is auto-detected from TPM firmware version and the file:
Comment thread
aidangarske marked this conversation as resolved.
- Generation 1 (e.g. 1.771): Non-LMS format (321 byte manifest)
- Generation 9 below 512: Non-LMS format (177 byte manifest)
- Generation 9 at 512 and above: LMS format (2697 byte manifest)

# Run without arguments to display the current firmware information
./st33_fw_update
Expand All @@ -156,8 +161,8 @@ TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1
TPM2_Startup pass
Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0)
Firmware version details: Major=9, Minor=257, Vendor=0x0
Hardware: ST33K (legacy firmware, Generation 1)
Firmware update: Non-LMS format required
Hardware: ST33K (generation 9 firmware below 512)
Firmware update: Non-LMS format required (177 byte manifest)

# Run with firmware file (format auto-detected from TPM version)
./st33_fw_update TPM_ST33KTPM2X_00090200_V1.fi
Expand All @@ -167,9 +172,9 @@ TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1
TPM2_Startup pass
Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0)
Firmware version details: Major=9, Minor=257, Vendor=0x0
Hardware: ST33K (legacy firmware, Generation 1)
Firmware update: Non-LMS format required
Format: Non-LMS (from TPM firmware version)
Hardware: ST33K (generation 9 firmware below 512)
Firmware update: Non-LMS format required (177 byte manifest)
Format: Non-LMS (blob0 177 bytes, verified against the block chain)
Firmware Update:
Total file size: 364290 bytes
Manifest (blob0): 177 bytes
Expand All @@ -178,17 +183,17 @@ Firmware Update:
Firmware update completed successfully.
Please reset or power cycle the TPM.

# Example with LMS firmware (Generation 2 TPM, firmware >= 512)
# Example with LMS firmware (generation 9 TPM, firmware at 512 and above)
./st33_fw_update ST33KTPM2X_FAC_00090200_V2.fi
ST33 Firmware Update Tool
Firmware File: ST33KTPM2X_FAC_00090200_V2.fi
TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 3
TPM2_Startup pass
Mfg STM (2), Vendor ST33KTPM2X, Fw 9.512 (0x0)
Firmware version details: Major=9, Minor=512, Vendor=0x0
Hardware: ST33K (modern firmware, Generation 2)
Firmware update: LMS format required
Format: LMS (from TPM firmware version)
Hardware: ST33K (generation 9 firmware at 512 and above)
Firmware update: LMS format required (2697 byte manifest)
Format: LMS (blob0 2697 bytes, verified against the block chain)
Firmware Update:
Total file size: 360092 bytes
Manifest (blob0): 2697 bytes
Expand All @@ -204,8 +209,8 @@ TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1
TPM2_Startup pass
Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0)
Firmware version details: Major=9, Minor=257, Vendor=0x0
Hardware: ST33K (legacy firmware, Generation 1)
Firmware update: Non-LMS format required
Hardware: ST33K (generation 9 firmware below 512)
Firmware update: Non-LMS format required (177 byte manifest)
Firmware Update Abandon:
Success: Please reset or power cycle TPM
```
Expand Down
6 changes: 6 additions & 0 deletions examples/firmware/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ EXTRA_DIST += examples/firmware/ifx_fw_extract.c
# Shared caller-supplied policy authorization helpers for the firmware examples
EXTRA_DIST += examples/firmware/firmware_policy.c
EXTRA_DIST += examples/firmware/firmware_policy.h
EXTRA_DIST += examples/firmware/st33_blob0.c
EXTRA_DIST += examples/firmware/st33_blob0.h

if BUILD_EXAMPLES
if BUILD_FIRMWARE

noinst_HEADERS += examples/firmware/firmware_policy.h
noinst_HEADERS += examples/firmware/st33_blob0.h

if BUILD_INFINEON
noinst_PROGRAMS += examples/firmware/ifx_fw_update
Expand All @@ -30,6 +33,7 @@ if BUILD_ST33
noinst_PROGRAMS += examples/firmware/st33_fw_update
examples_firmware_st33_fw_update_SOURCES = examples/firmware/st33_fw_update.c \
examples/firmware/firmware_policy.c \
examples/firmware/st33_blob0.c \
examples/tpm_test_keys.c
examples_firmware_st33_fw_update_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD)
examples_firmware_st33_fw_update_DEPENDENCIES = src/libwolftpm.la
Expand All @@ -41,6 +45,8 @@ endif
example_firmwaredir = $(exampledir)/firmware
dist_example_firmware_DATA = examples/firmware/firmware_policy.c \
examples/firmware/firmware_policy.h \
examples/firmware/st33_blob0.c \
examples/firmware/st33_blob0.h \
examples/firmware/ifx_fw_update.c \
examples/firmware/st33_fw_update.c

Expand Down
97 changes: 97 additions & 0 deletions examples/firmware/st33_blob0.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* st33_blob0.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfTPM.
*
* wolfTPM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfTPM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <examples/firmware/st33_blob0.h>

const size_t st33_blob0_sizes[ST33_BLOB0_SIZE_CNT] = {
ST33_BLOB0_SIZE_NON_LMS_RSA,
ST33_BLOB0_SIZE_NON_LMS,
ST33_BLOB0_SIZE_LMS
};

size_t st33_expected_blob0(word32 fwVerMajor, word32 fwVerMinor)
{
if (fwVerMajor < ST33_BLOB0_GENERATION_LMS_CAPABLE) {
return ST33_BLOB0_SIZE_NON_LMS_RSA;
}
if (fwVerMinor < ST33_BLOB0_VERSION_LMS_REQUIRED) {
return ST33_BLOB0_SIZE_NON_LMS;
}
return ST33_BLOB0_SIZE_LMS;
}

size_t st33_blob0_candidates(word32 fwVerMajor, word32 fwVerMinor,
int haveCaps, size_t* cand)
{
size_t idx;
size_t candCnt = 0;

if (cand == NULL) {
return 0;
}
if (haveCaps) {
cand[candCnt++] = st33_expected_blob0(fwVerMajor, fwVerMinor);
}
for (idx = 0; idx < ST33_BLOB0_SIZE_CNT; idx++) {
if (candCnt == 0 || cand[0] != st33_blob0_sizes[idx]) {
cand[candCnt++] = st33_blob0_sizes[idx];
}
}
return candCnt;
}

size_t st33_detect_blob0(const byte* buf, size_t bufSz, const size_t* cand,
size_t candCnt)
{
size_t i, off, len;

if (buf == NULL || cand == NULL) {
return 0;
}
for (i = 0; i < candCnt; i++) {
if (bufSz <= cand[i]) {
continue;
}
off = cand[i];
while (off + 3 <= bufSz) {
if (buf[off] == 0) {
break; /* end marker, not a record */
}
len = ((size_t)buf[off + 1] << 8) | buf[off + 2];
/* Reject rather than walk past the end: a payload that does not
* fit means this candidate is not where blob0 ends. Checked as a
* subtraction on the remaining bytes so off + 3 + len can never
* be formed out of range. */
if (len == 0 || len > bufSz - off - 3) {
break;
}
off += 3 + len;
}
if (off == bufSz) {
return cand[i];
}
}
return 0;
}
78 changes: 78 additions & 0 deletions examples/firmware/st33_blob0.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* st33_blob0.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfTPM.
*
* wolfTPM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfTPM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* ST33 firmware image (.fi) layout helpers, split out of st33_fw_update.c so
* the block-chain parser that decides where the manifest ends can be unit
* tested. Pure buffer logic - no TPM calls, no wolfCrypt. */

#ifndef WOLFTPM_EXAMPLE_ST33_BLOB0_H
#define WOLFTPM_EXAMPLE_ST33_BLOB0_H

#include <wolftpm/tpm2_types.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/* The manifest (blob0) is a 33 byte fixed header followed by the firmware
* digest and the signature over it, so its size follows the algorithms that
* generation signs with. */
/* gen 1: SHA-256 + RSAPSS-2048 */
#define ST33_BLOB0_SIZE_NON_LMS_RSA 321
/* gen 9 below 512: SHA-384 + ECDSA P-384 */
#define ST33_BLOB0_SIZE_NON_LMS 177
/* gen 9 at 512 and above: embedded LMS signature */
#define ST33_BLOB0_SIZE_LMS 2697

/* LMS is a generation 9 rule. Generation 1 parts are always non-LMS no matter
* how high the minor version goes (e.g. 1.771). Mirrors
* ST33_FW_GENERATION_LMS_CAPABLE / ST33_FW_VERSION_LMS_REQUIRED in
* src/tpm2_wrap.c, which is the authority the library validates against. */
#define ST33_BLOB0_GENERATION_LMS_CAPABLE 9
#define ST33_BLOB0_VERSION_LMS_REQUIRED 512

#define ST33_BLOB0_SIZE_CNT 3
extern const size_t st33_blob0_sizes[ST33_BLOB0_SIZE_CNT];

/* Manifest size the running firmware expects for its next update. Takes the
* version fields rather than WOLFTPM2_CAPS so it stays free of the wrapper. */
size_t st33_expected_blob0(word32 fwVerMajor, word32 fwVerMinor);

/* Fill cand (at least ST33_BLOB0_SIZE_CNT entries) with every known manifest
* size. When haveCaps is set the size the firmware version implies is placed
* first, so it wins if more than one candidate parses. Returns the count. */
size_t st33_blob0_candidates(word32 fwVerMajor, word32 fwVerMinor,
int haveCaps, size_t* cand);

/* Confirm a candidate blob0 size by walking the block chain that follows it.
* Every byte after blob0 is a [type:1][len:2 big-endian][payload] record and
* the chain ends exactly at end of file, so only the correct size lands on
* the final byte. Candidates are tried in the supplied order. Returns the
* blob0 size, or 0 when the file does not parse with any candidate. */
size_t st33_detect_blob0(const byte* buf, size_t bufSz, const size_t* cand,
size_t candCnt);

#ifdef __cplusplus
}
#endif

#endif /* WOLFTPM_EXAMPLE_ST33_BLOB0_H */
Loading
Loading