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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ STMicro ST33TPHF2XSPI
TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e
Mfg STM (2), Vendor , Fw 74.8 (1151341959), FIPS 140-2 1, CC-EAL4 0

STMicro ST33TPHF2XSPI (newer firmware line)
TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e
Mfg STM (2), Vendor , Fw 1.258 (0x0), FIPS 140-2 1, CC-EAL4 0

STMicro ST33TPHF2XI2C
TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e
Mfg STM (2), Vendor , Fw 74.9 (1151341959), FIPS 140-2 1, CC-EAL4 0
Expand All @@ -275,6 +279,13 @@ Microchip ATTPM20
TPM2: Caps 0x30000695, Did 0x3205, Vid 0x1114, Rid 0x 1
Mfg MCHP (3), Vendor , Fw 512.20481 (0), FIPS 140-2 0, CC-EAL4 0

Note: ST33TPHF2X parts report `TPM_PT_VENDOR_STRING_1..4` as zero or as
non-printable bytes, so the `Vendor` field prints empty. The firmware major version identifies the line
instead: 1.x and 2.x are ST33TPHF2X (SPI and I2C firmware respectively), 9.x is
ST33KTPM2X and 10.x is ST33KTPM2A. See
[examples/firmware/README.md](examples/firmware/README.md) for how this selects
the firmware update format and command codes.

Nations Technologies Inc. Z32H330 TPM 2.0 module
Mfg NTZ (0), Vendor Z32H330, Fw 7.51 (419631892), FIPS 140-2 0, CC-EAL4 0

Expand Down
72 changes: 63 additions & 9 deletions examples/firmware/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,49 @@ The manifest (blob0) is a 33 byte fixed header followed by the firmware digest a

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.

### Identifying the part

ST33TPHF2X parts report `TPM_PT_VENDOR_STRING_1..4` as zero or as non-printable bytes, so unlike an ST33KTPM they print an empty `Vendor` field. `st33_fw_update` dumps the raw bytes so they can still be compared. What identifies them is the firmware major version, which tracks the part and interface line:

| `fwVerMajor` | Part line | Example firmware image |
| --- | --- | --- |
| 1 | ST33TPHF2X, SPI firmware line | `TPM_ST33TPHF2XSPI_00010301.fi` |
| 2 | ST33TPHF2X, I2C firmware line | `TPM_ST33TPHF2XI2C_00020200.fi` |
| 9 | ST33KTPM2X | `TPM_ST33KTPM2X_00090200_V1.fi` |
| 10 (`0x000a`) | ST33KTPM2A | `TPM_ST33KTPM2A_000a0200.fi` |
| 11 (`0x000b`) | ST33KTPMQ | (none on hand) |

The manifest header carries the same version: a zero byte followed by the firmware version the image upgrades to, in the `TPM_PT_FIRMWARE_VERSION_1` layout (`00 | 00 02 02 00` is 2.512). `st33_fw_update` prints both and refuses an image whose major version does not match the running part.

### Field upgrade command codes

ST33 implements the field upgrade with one of two command code pairs, and the wrong one is answered with `TPM_RC_COMMAND_CODE` (`0x143`) before the manifest is even parsed:

| Pair | Start | Data |
| --- | --- | --- |
| Standard TCG | `TPM_CC_FieldUpgradeStart` (`0x0000012F`) | `TPM_CC_FieldUpgradeData` (`0x00000141`) |
| ST33KTPM vendor | `0x2000030C` | `0x2000030D` |

wolfTPM asks the TPM which pair it implements, by querying `TPM_CAP_COMMANDS` for the two start codes. That is authoritative and needs no table of parts. ST's own reference tool instead infers the pair from version numbers (standard codes when the running firmware minor version is below 256, or when the image targets firmware generation 2), and wolfTPM falls back to that same rule -- `wolfTPM2_ST33_FwUpgradeCommands()` -- only when the TPM will not answer, which is the case once it has entered firmware upgrade mode, or when it lists both pairs.

The probe matters: an ST33KTPMQ at firmware 11.1 implements **only** the vendor pair even though its minor version is below 256, so the version rule alone would pick the wrong codes for it.

Nothing needs to be selected by hand. When a caller-supplied policy is used, the `PolicyCommandCode` is bound to whichever start code will actually be sent, and `st33_fw_update` reports whether the codes came from the TPM or were inferred.

Running `st33_fw_update` with no firmware file also reports which of the four codes the attached part implements, read from `TPM_CAP_COMMANDS`. This is read-only and is the quickest way to diagnose a `TPM_RC_COMMAND_CODE` on a new part:

```sh
./st33_fw_update
...
Field upgrade command set:
0x0000012f FieldUpgradeStart (standard): implemented
0x00000141 FieldUpgradeData (standard): implemented
0x2000030c FieldUpgradeStartVendor (ST33KTPM): not implemented
0x2000030d FieldUpgradeDataVendor (ST33KTPM): not implemented
```

A firmware major version outside the known families is treated as unknown rather than guessed at: no manifest size is asserted for it, the tool reports that the size is taken from the image, and the block-chain check in `st33_detect_blob0` establishes the real size from the file itself. That way a part from a newer line, such as an ST33KTPMQ, is not refused an image on the strength of a rule that does not apply to it.

### Updating the firmware

The `st33_fw_update` tool automatically detects the firmware format.
Expand All @@ -154,15 +197,23 @@ Firmware format is auto-detected from TPM firmware version and the file:
- 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
# Run without arguments to display the current firmware information.
# This capture is an ST33TPHF2XSPI, which implements only the vendor codes.
./st33_fw_update
ST33 Firmware Update Tool
TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1
TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e
TPM2_Startup pass
Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0)
Firmware version details: Major=9, Minor=257, Vendor=0x0
Hardware: ST33K (generation 9 firmware below 512)
Firmware update: Non-LMS format required (177 byte manifest)
Mfg STM (2), Vendor , Fw 1.258 (0x0)
Vendor string bytes: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Firmware version details: Major=1, Minor=258, Vendor=0x0
Part line: ST33TPHF2X (SPI firmware line)
Firmware generation: 1
Firmware update: Non-LMS format required (321 byte manifest)
Field upgrade command set:
0x0000012f FieldUpgradeStart (standard): not implemented
0x00000141 FieldUpgradeData (standard): not implemented
0x2000030c FieldUpgradeStartVendor (ST33KTPM): implemented
0x2000030d FieldUpgradeDataVendor (ST33KTPM): implemented

# Run with firmware file (format auto-detected from TPM version)
./st33_fw_update TPM_ST33KTPM2X_00090200_V1.fi
Expand All @@ -172,13 +223,16 @@ 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 (generation 9 firmware below 512)
Part line: ST33KTPM2X
Firmware generation: 9 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
Firmware data: 364113 bytes
Image targets firmware: 9.512 (ST33KTPM2X)
Command codes: start 0x2000030c, data 0x2000030d
...
Firmware update completed successfully.
Please reset or power cycle the TPM.
Expand All @@ -191,7 +245,7 @@ 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 (generation 9 firmware at 512 and above)
Firmware generation: 9 at 512 and above
Firmware update: LMS format required (2697 byte manifest)
Format: LMS (blob0 2697 bytes, verified against the block chain)
Firmware Update:
Expand All @@ -209,7 +263,7 @@ 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 (generation 9 firmware below 512)
Firmware generation: 9 below 512
Firmware update: Non-LMS format required (177 byte manifest)
Firmware Update Abandon:
Success: Please reset or power cycle TPM
Expand Down
37 changes: 30 additions & 7 deletions examples/firmware/st33_blob0.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,51 @@ const size_t st33_blob0_sizes[ST33_BLOB0_SIZE_CNT] = {
ST33_BLOB0_SIZE_LMS
};

size_t st33_expected_blob0(word32 fwVerMajor, word32 fwVerMinor)
int st33_blob0_family(word32 fwVerMajor)
{
if (fwVerMajor < ST33_BLOB0_GENERATION_LMS_CAPABLE) {
return ST33_BLOB0_SIZE_NON_LMS_RSA;
switch (fwVerMajor) {
case 1: /* ST33TPHF2X, SPI firmware line */
case 2: /* ST33TPHF2X, I2C firmware line */
case 74: /* ST33TPHF2X, older line both buses (74.8 SPI, 74.9 I2C) */
return ST33_BLOB0_FAMILY_TPHF2X;
case 9: /* ST33KTPM2X */
case 10: /* ST33KTPM2A */
return ST33_BLOB0_FAMILY_KTPM;
default:
return ST33_BLOB0_FAMILY_UNKNOWN;
}
if (fwVerMinor < ST33_BLOB0_VERSION_LMS_REQUIRED) {
return ST33_BLOB0_SIZE_NON_LMS;
}

size_t st33_expected_blob0(word32 fwVerMajor, word32 fwVerMinor)
{
switch (st33_blob0_family(fwVerMajor)) {
case ST33_BLOB0_FAMILY_TPHF2X:
return ST33_BLOB0_SIZE_NON_LMS_RSA;
case ST33_BLOB0_FAMILY_KTPM:
if (fwVerMinor < ST33_BLOB0_VERSION_LMS_REQUIRED) {
return ST33_BLOB0_SIZE_NON_LMS;
}
return ST33_BLOB0_SIZE_LMS;
default:
return 0; /* unknown family, assert nothing */
}
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;
size_t expected;

if (cand == NULL) {
return 0;
}
if (haveCaps) {
cand[candCnt++] = st33_expected_blob0(fwVerMajor, fwVerMinor);
expected = st33_expected_blob0(fwVerMajor, fwVerMinor);
if (expected != 0) {
cand[candCnt++] = expected;
}
}
for (idx = 0; idx < ST33_BLOB0_SIZE_CNT; idx++) {
if (candCnt == 0 || cand[0] != st33_blob0_sizes[idx]) {
Expand Down
23 changes: 16 additions & 7 deletions examples/firmware/st33_blob0.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,27 @@ extern "C" {
/* 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
/* The manifest format follows the silicon family, which the firmware major
* version identifies. ST33TPHF2X (majors 1, 2 and the older 74 line) signs
* with SHA-256 + RSA-PSS; ST33KTPM (majors 9 and 10) signs with ECDSA P-384,
* and from minor 512 with LMS. A major outside both lists is unknown, and no
* size is asserted for it. Mirrors src/tpm2_wrap.c, which is the authority
* the library validates against. */
#define ST33_BLOB0_FAMILY_UNKNOWN 0
#define ST33_BLOB0_FAMILY_TPHF2X 1
#define ST33_BLOB0_FAMILY_KTPM 2
#define ST33_BLOB0_VERSION_LMS_REQUIRED 512

/* Silicon family for a firmware major version, ST33_BLOB0_FAMILY_UNKNOWN when
* the major is not one this release knows about. */
int st33_blob0_family(word32 fwVerMajor);

#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. */
* version fields rather than WOLFTPM2_CAPS so it stays free of the wrapper.
* Returns 0 when the family is unknown, meaning no size can be asserted. */
size_t st33_expected_blob0(word32 fwVerMajor, word32 fwVerMinor);

/* Fill cand (at least ST33_BLOB0_SIZE_CNT entries) with every known manifest
Expand Down
Loading
Loading