|
51 | 51 | /******************************************************************************/ |
52 | 52 |
|
53 | 53 | /* Manifest sizes per ST33 firmware format */ |
54 | | -#define ST33_BLOB0_SIZE_NON_LMS 177 /* Non-LMS manifest size */ |
55 | | -#define ST33_BLOB0_SIZE_LMS 2697 /* LMS manifest size (includes embedded signature) */ |
| 54 | +/* The manifest is a 33 byte fixed header plus the firmware digest and the |
| 55 | + * signature over it, so its size follows the algorithms of that generation. */ |
| 56 | +/* gen 1: SHA-256 + RSAPSS-2048 */ |
| 57 | +#define ST33_BLOB0_SIZE_NON_LMS_RSA 321 |
| 58 | +/* gen 9 below 512: SHA-384 + ECDSA P-384 */ |
| 59 | +#define ST33_BLOB0_SIZE_NON_LMS 177 |
| 60 | +/* gen 9 at 512 and above: embedded LMS signature */ |
| 61 | +#define ST33_BLOB0_SIZE_LMS 2697 |
| 62 | + |
| 63 | +static const size_t st33_blob0_sizes[] = { |
| 64 | + ST33_BLOB0_SIZE_NON_LMS_RSA, |
| 65 | + ST33_BLOB0_SIZE_NON_LMS, |
| 66 | + ST33_BLOB0_SIZE_LMS |
| 67 | +}; |
| 68 | +#define ST33_BLOB0_SIZE_CNT \ |
| 69 | + (sizeof(st33_blob0_sizes) / sizeof(st33_blob0_sizes[0])) |
| 70 | + |
| 71 | +/* Confirm a candidate blob0 size by walking the block chain that follows it. |
| 72 | + * Every byte after blob0 is a [type:1][len:2 big-endian][payload] record and |
| 73 | + * the chain ends exactly at end of file, so only the correct size lands on |
| 74 | + * the final byte. Candidates are tried in the supplied order, so the size the |
| 75 | + * TPM firmware version implies wins when more than one could fit. Returns the |
| 76 | + * blob0 size, or 0 when the file does not parse with any known size. */ |
| 77 | +static size_t st33_detect_blob0(const byte* buf, size_t bufSz, |
| 78 | + const size_t* cand, size_t candCnt) |
| 79 | +{ |
| 80 | + size_t i, off, len; |
| 81 | + |
| 82 | + for (i = 0; i < candCnt; i++) { |
| 83 | + if (bufSz <= cand[i]) { |
| 84 | + continue; |
| 85 | + } |
| 86 | + off = cand[i]; |
| 87 | + while (off + 3 <= bufSz) { |
| 88 | + if (buf[off] == 0) { |
| 89 | + break; /* end marker, not a record */ |
| 90 | + } |
| 91 | + len = ((size_t)buf[off + 1] << 8) | buf[off + 2]; |
| 92 | + if (len == 0) { |
| 93 | + break; |
| 94 | + } |
| 95 | + off += 3 + len; |
| 96 | + } |
| 97 | + if (off == bufSz) { |
| 98 | + return cand[i]; |
| 99 | + } |
| 100 | + } |
| 101 | + return 0; |
| 102 | +} |
| 103 | + |
| 104 | +/* Manifest size the running firmware expects for its next update */ |
| 105 | +static size_t st33_expected_blob0(WOLFTPM2_CAPS* caps) |
| 106 | +{ |
| 107 | + if (caps->fwVerMajor < 9) { |
| 108 | + return ST33_BLOB0_SIZE_NON_LMS_RSA; |
| 109 | + } |
| 110 | + if (caps->fwVerMinor < 512) { |
| 111 | + return ST33_BLOB0_SIZE_NON_LMS; |
| 112 | + } |
| 113 | + return ST33_BLOB0_SIZE_LMS; |
| 114 | +} |
56 | 115 |
|
57 | 116 | static void usage(void) |
58 | 117 | { |
@@ -203,6 +262,9 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) |
203 | 262 | fw_info_t fwinfo; |
204 | 263 | int abandon = 0; |
205 | 264 | size_t blob0_size; |
| 265 | + size_t cand[ST33_BLOB0_SIZE_CNT + 1]; |
| 266 | + size_t candCnt; |
| 267 | + size_t idx; |
206 | 268 | int i; |
207 | 269 | #ifdef WOLFTPM_HAVE_FW_POLICY |
208 | 270 | int policytest = 0; |
@@ -372,50 +434,39 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) |
372 | 434 | } |
373 | 435 |
|
374 | 436 | load_firmware: |
375 | | - /* Determine blob0 (manifest) size based on firmware version. |
376 | | - * In upgrade mode (caps not available), auto-detect from file size. */ |
377 | | - if (fwinfo.in_upgrade_mode) { |
378 | | - /* In upgrade mode, we don't have caps. Load file first to detect format. */ |
379 | | - rc = loadFile(fi_file, &fwinfo.fi_buf, &fwinfo.fi_bufSz); |
380 | | - if (rc != 0) { |
381 | | - printf("Failed to load firmware file: %s\n", fi_file); |
382 | | - goto exit; |
383 | | - } |
384 | | - /* Auto-detect format from file size: LMS files are larger due to |
385 | | - * 2697 byte manifest vs 177 byte manifest */ |
386 | | - if (fwinfo.fi_bufSz > ST33_BLOB0_SIZE_LMS + 1000) { |
387 | | - /* File large enough to potentially be LMS format. |
388 | | - * Check if blob header at LMS offset looks valid. */ |
389 | | - if (fwinfo.fi_buf[ST33_BLOB0_SIZE_LMS] != 0 && |
390 | | - fwinfo.fi_buf[ST33_BLOB0_SIZE_LMS] != 0xFF) { |
391 | | - blob0_size = ST33_BLOB0_SIZE_LMS; |
392 | | - printf("\tFormat: LMS (auto-detected from file)\n"); |
393 | | - } |
394 | | - else { |
395 | | - blob0_size = ST33_BLOB0_SIZE_NON_LMS; |
396 | | - printf("\tFormat: Non-LMS (auto-detected from file)\n"); |
397 | | - } |
398 | | - } |
399 | | - else { |
400 | | - blob0_size = ST33_BLOB0_SIZE_NON_LMS; |
401 | | - printf("\tFormat: Non-LMS (auto-detected from file)\n"); |
402 | | - } |
| 437 | + /* Load the complete .fi file, then determine the blob0 (manifest) size. |
| 438 | + * In upgrade mode caps are unavailable, so no size is preferred and the |
| 439 | + * block chain alone decides. */ |
| 440 | + rc = loadFile(fi_file, &fwinfo.fi_buf, &fwinfo.fi_bufSz); |
| 441 | + if (rc != 0) { |
| 442 | + printf("Failed to load firmware file: %s\n", fi_file); |
| 443 | + goto exit; |
403 | 444 | } |
404 | | - else { |
405 | | - /* Normal mode: determine format from firmware version */ |
406 | | - blob0_size = (caps.fwVerMinor >= 512) ? |
407 | | - ST33_BLOB0_SIZE_LMS : ST33_BLOB0_SIZE_NON_LMS; |
408 | | - printf("\tFormat: %s (from TPM firmware version)\n", |
409 | | - (caps.fwVerMinor >= 512) ? "LMS" : "Non-LMS"); |
410 | | - |
411 | | - /* Load the complete .fi file */ |
412 | | - rc = loadFile(fi_file, &fwinfo.fi_buf, &fwinfo.fi_bufSz); |
413 | | - if (rc != 0) { |
414 | | - printf("Failed to load firmware file: %s\n", fi_file); |
415 | | - goto exit; |
| 445 | + |
| 446 | + candCnt = 0; |
| 447 | + if (!fwinfo.in_upgrade_mode) { |
| 448 | + cand[candCnt++] = st33_expected_blob0(&caps); |
| 449 | + } |
| 450 | + for (idx = 0; idx < ST33_BLOB0_SIZE_CNT; idx++) { |
| 451 | + if (candCnt == 0 || cand[0] != st33_blob0_sizes[idx]) { |
| 452 | + cand[candCnt++] = st33_blob0_sizes[idx]; |
416 | 453 | } |
417 | 454 | } |
418 | 455 |
|
| 456 | + blob0_size = st33_detect_blob0(fwinfo.fi_buf, fwinfo.fi_bufSz, cand, |
| 457 | + candCnt); |
| 458 | + if (blob0_size == 0) { |
| 459 | + printf("Error: could not determine the manifest (blob0) size of %s\n", |
| 460 | + fi_file); |
| 461 | + printf(" The %zu byte file does not parse as an ST33 firmware image " |
| 462 | + "with a\n 321, 177 or 2697 byte manifest.\n", fwinfo.fi_bufSz); |
| 463 | + rc = BAD_FUNC_ARG; |
| 464 | + goto exit; |
| 465 | + } |
| 466 | + printf("\tFormat: %s (blob0 %zu bytes, verified against the block " |
| 467 | + "chain)\n", |
| 468 | + (blob0_size == ST33_BLOB0_SIZE_LMS) ? "LMS" : "Non-LMS", blob0_size); |
| 469 | + |
419 | 470 | /* Validate file size */ |
420 | 471 | if (fwinfo.fi_bufSz <= blob0_size) { |
421 | 472 | printf("Error: Firmware file too small. Expected > %zu bytes, got %zu bytes.\n", |
|
0 commit comments