diff --git a/.cyignore b/.cyignore new file mode 100644 index 0000000..0a3ff1d --- /dev/null +++ b/.cyignore @@ -0,0 +1,4 @@ +# wolfTPM folders +$(SEARCH_wolftpm)/IDE +$(SEARCH_wolftpm)/examples +$(SEARCH_wolftpm)/tests \ No newline at end of file diff --git a/.gitignore b/.gitignore index b8b7b2a..ea9d1b8 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,8 @@ examples/attestation/activate_credential examples/boot/secure_rot examples/boot/secret_seal examples/boot/secret_unseal +examples/firmware/ifx_fw_extract +examples/firmware/ifx_fw_update # Generated Cert Files certs/ca-*.pem diff --git a/Makefile.am b/Makefile.am index 90c1148..dc750f0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,6 +43,7 @@ include wrapper/include.am include hal/include.am include cmake/include.am +EXTRA_DIST+= .cyignore EXTRA_DIST+= README.md EXTRA_DIST+= ChangeLog.md EXTRA_DIST+= LICENSE diff --git a/configure.ac b/configure.ac index 7d2101e..0841058 100644 --- a/configure.ac +++ b/configure.ac @@ -408,6 +408,18 @@ then fi +# Built-in TPM firmware upgrade support +AC_ARG_ENABLE([firmware], + [AS_HELP_STRING([--enable-firmware],[Enable support for TPM firmware upgrades (default: enabled)])], + [ ENABLED_FIRMWARE=$enableval ], + [ ENABLED_FIRMWARE=yes ] + ) +if test "x$ENABLED_FIRMWARE" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_FIRMWARE_UPGRADE" +fi + + # HARDEN FLAGS AX_HARDEN_CC_COMPILER_FLAGS @@ -431,6 +443,7 @@ AM_CONDITIONAL([BUILD_WINAPI], [test "x$ENABLED_WINAPI" = "xyes"]) AM_CONDITIONAL([BUILD_NUVOTON], [test "x$ENABLED_NUVOTON" = "xyes"]) AM_CONDITIONAL([BUILD_CHECKWAITSTATE], [test "x$ENABLED_CHECKWAITSTATE" = "xyes"]) AM_CONDITIONAL([BUILD_AUTODETECT], [test "x$ENABLED_AUTODETECT" = "xyes"]) +AM_CONDITIONAL([BUILD_FIRMWARE], [test "x$ENABLED_FIRMWARE" = "xyes"]) AM_CONDITIONAL([BUILD_HAL], [test "x$ENABLED_EXAMPLE_HAL" = "xyes" || test "x$ENABLED_MMIO" = "xyes"]) @@ -556,3 +569,4 @@ echo " * Microchip ATTPM20: $ENABLED_MICROCHIP" echo " * Nuvoton NPCT75x: $ENABLED_NUVOTON" echo " * Runtime Module Detection: $ENABLED_AUTODETECT" +echo " * Firmware Upgrade Support: $ENABLED_FIRMWARE" diff --git a/examples/boot/include.am b/examples/boot/include.am index d7ec884..7a19340 100644 --- a/examples/boot/include.am +++ b/examples/boot/include.am @@ -1,6 +1,8 @@ # vim:ft=automake # All paths should be given relative to the root +EXTRA_DIST += examples/boot/README.md + if BUILD_EXAMPLES noinst_HEADERS += examples/boot/boot.h diff --git a/examples/firmware/Makefile b/examples/firmware/Makefile new file mode 100644 index 0000000..1bc53d2 --- /dev/null +++ b/examples/firmware/Makefile @@ -0,0 +1,13 @@ +CC=gcc +CFLAGS=-Wall -Werror -Wextra -g +LIBS= + +all: clean ifx_fw_extract + +ifx_fw_extract: ifx_fw_extract.o + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + +.PHONY: clean + +clean: + rm -f *.o ifx_fw_extract diff --git a/examples/firmware/README.md b/examples/firmware/README.md new file mode 100644 index 0000000..45e4a60 --- /dev/null +++ b/examples/firmware/README.md @@ -0,0 +1,104 @@ +# TPM Firmware Update Support + +Currently wolfTPM supports firmware update capability for the Infineon SLB9672 (SPI) and SLB9673 (I2C) TPM 2.0 modules. Infineon has open sourced their firmware update. + +## Infineon Firmware + +### Extracting the firmware + +Infineon releases firmware as a .bin file (example: TPM20_15.23.17664.0_R1.BIN). + +The .bin contains a 16-byte GUID header, at least one manifest based on key group and the firmware. A typical manifest is 3KB and firmware is 920KB. + +We have included a host side tool `ifx_fw_extract` for extracting the manifest and firmware data file required for a TPM upgrade. + +Example usage: + +```sh +# Build host tool +make + +# Help +./ifx_fw_extract --help +Usage: + ifx_fw_extract + ifx_fw_extract + +# Find key groups in .bin +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 + +# Extract manifest and firmware data files for key group +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN 7 TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 +Chosen group found: 00000007 +Manifest size is 3224 +Data size is 934693 +Writing TPM20_26.13.17770.0_R1.MANIFEST +Writing TPM20_26.13.17770.0_R1.DATA +``` + +### Updating the firmware + +The `ifx_fw_update` tool uses the manifest (header) and firmware data file. + +The TPM has a vendor capability for getting the key group id. This is populated in the `WOLFTPM2_CAPS.keyGroupId` when `wolfTPM2_GetCapabilities` is called. This value should match the firmware extract tool `keygroup_id`. + +```sh +# Help +./ifx_fw_update --help +Infineon Firmware Update Usage: + ./ifx_fw_update (get info) + ./ifx_fw_update --abandon (cancel) + ./ifx_fw_update + +# Run without arguments to display the current firmware information including key group id and operational mode +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) + +# Run with manifest and firmware files +./ifx_fw_update TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Infineon Firmware Update Tool + Manifest File: TPM20_26.13.17770.0_R1.MANIFEST + Firmware File: TPM20_26.13.17770.0_R1.DATA +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +TPM2_FlushContext: Closed handle 0x3000000 +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +Firmware manifest chunk 1024 offset (0 / 3224), state 1 +Firmware manifest chunk 1024 offset (1024 / 3224), state 2 +Firmware manifest chunk 1024 offset (2048 / 3224), state 2 +Firmware manifest chunk 152 offset (3072 / 3224), state 0 +Firmware data chunk offset 0 +Firmware data chunk offset 1024 +Firmware data chunk offset 2048 +Firmware data chunk offset 3072 +... +Firmware data chunk offset 932864 +Firmware data chunk offset 933888 +Firmware data done +Mfg IFX (1), Vendor , Fw 0.0 (0x0) +Operational mode: After finalize or abandon, reboot required (0x4) +KeyGroupId 0x7, FwCounter 1253 (254 same) +TPM2_Shutdown failed 304: Unknown + +# Reset or power cycle TPM +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1253 (254 same) +``` diff --git a/examples/firmware/ifx_fw_extract.c b/examples/firmware/ifx_fw_extract.c new file mode 100644 index 0000000..7888489 --- /dev/null +++ b/examples/firmware/ifx_fw_extract.c @@ -0,0 +1,321 @@ +/* ifx_fw_extract.c + * + * Copyright (C) 2006-2024 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 2 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 + */ + +/* Tool source based on simple-update example from + * Infineon Technologies AG (www.infineon.com). + * This is a stand-alone host side tool for extracting the firmware + * manifest and data files from a supplied .bin + */ + +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Endianess helpers */ +#if defined(__MACH__) || defined(__APPLE__) + #include + #include + + #define htobe16(x) OSSwapHostToBigInt16(x) + #define htole16(x) OSSwapHostToLittleInt16(x) + #define be16toh(x) OSSwapBigToHostInt16(x) + #define le16toh(x) OSSwapLittleToHostInt16(x) + + #define htobe32(x) OSSwapHostToBigInt32(x) + #define htole32(x) OSSwapHostToLittleInt32(x) + #define be32toh(x) OSSwapBigToHostInt32(x) + #define le32toh(x) OSSwapLittleToHostInt32(x) + + #define htobe64(x) OSSwapHostToBigInt64(x) + #define htole64(x) OSSwapHostToLittleInt64(x) + #define be64toh(x) OSSwapBigToHostInt64(x) + #define le64toh(x) OSSwapLittleToHostInt64(x) +#else + #include +#endif + +/* Helper to print file and line */ +#define LOG(t) { printf(__FILE__":%i: %s\n", __LINE__, t); } + +#define READ_BE16(dest, buf, size, off) { \ + if (off + sizeof(dest) >= size) { \ + LOG("FW file too short"); \ + return -1; \ + } \ + memcpy(&dest, &fw[off], sizeof(dest)); \ + dest = be16toh(dest); \ + off += sizeof(dest); \ +} + +#define READ_BE32(dest, buf, size, off) { \ + if (off + sizeof(dest) >= size) { \ + LOG("FW file too short"); \ + return -1; \ + } \ + memcpy(&dest, &fw[off], sizeof(dest)); \ + dest = be32toh(dest); \ + off += sizeof(dest); \ +} + + +/* macros for stdio */ +#define XFILE FILE* +#define XFOPEN fopen +#define XFSEEK fseek +#define XFTELL ftell +#define XREWIND rewind +#define XFREAD fread +#define XFWRITE fwrite +#define XFCLOSE fclose +#define XSEEK_END SEEK_END +#define XBADFILE NULL +#define XFGETS fgets +#define XFEOF feof + +/* internal error codes */ +#define MEMORY_E -125 /* out of memory error */ +#define BUFFER_E -132 /* output buffer too small or input too large */ +#define BAD_FUNC_ARG -173 /* Bad function argument provided */ + + +static int extractFW( + uint8_t *fw, size_t fw_size, uint32_t keygroup_id, + uint8_t **manifest, size_t *manifest_size, + uint8_t **data, size_t *data_size) +{ + size_t offset = 0, offset2; + uint16_t size16, num; + uint32_t size32, group; + + const uint8_t guid[] = { 0x1a, 0x53, 0x66, 0x7a, + 0xfb, 0x12, 0x47, 0x9e, + 0xac, 0x58, 0xec, 0x99, + 0x58, 0x86, 0x10, 0x94 }; + + if (offset + sizeof(guid) > fw_size) { + LOG("FW file too short"); + return -1; + } + if (memcmp(&fw[offset], &guid[0], sizeof(guid)) != 0) { + LOG("Wrong GUID"); + return -1; + } + offset += sizeof(guid) + 1; + + READ_BE16(size16, fw, fw_size, offset); + offset += size16 + 1; + + READ_BE16(size16, fw, fw_size, offset); + offset += size16; + + READ_BE16(size16, fw, fw_size, offset); + offset2 = offset; + offset += size16; + + READ_BE16(size16, fw, offset, offset2); + offset2 += size16; + + READ_BE16(num, fw, offset, offset2); + + *manifest = NULL; + for (int i = 0; i < num; i++) { + READ_BE32(group, fw, offset, offset2); + printf("Found group %08x\n", group); + + READ_BE16(size16, fw, offset, offset2); + + if (group == keygroup_id) { + printf("Chosen group found: %08x\n", group); + *manifest = &fw[offset2]; + *manifest_size = size16; + } + offset2 += size16; + } + if (*manifest == NULL) { + if (keygroup_id == 0) { + /* just list key groups */ + return 0; + } + LOG("Chosen group not found"); + return -1; + } + + printf("Manifest size is %zi\n", *manifest_size); + if (offset2 != offset) { + LOG("Bad Manifest size"); + return -1; + } + + READ_BE32(size32, fw, fw_size, offset); + if (offset + size32 >= fw_size) { + LOG("FW file too short"); + return -1; + } + *data = &fw[offset]; + *data_size = size32; + offset += size32; + printf("Data size is %zi\n", *data_size); + + READ_BE16(size16, fw, fw_size, offset); + offset += size16 + 4; + + if (offset != fw_size) { + LOG("Wrong FW file size"); + printf("offset at %zi, fw_size at %zi\n", offset, fw_size); + return -1; + } + + return 0; +} + +static int readfile(const char* fname, uint8_t** buf, size_t* bufLen) +{ + int ret = 0; + ssize_t fileSz, readLen; + XFILE fp; + + if (fname == NULL || buf == NULL || bufLen == NULL) + return BAD_FUNC_ARG; + + /* open file (read-only binary) */ + fp = XFOPEN(fname, "rb"); + if (fp == XBADFILE) { + fprintf(stderr, "Error loading %s\n", fname); + return BUFFER_E; + } + + XFSEEK(fp, 0, XSEEK_END); + fileSz = XFTELL(fp); + XREWIND(fp); + if (fileSz > 0) { + if (*buf == NULL) { + *buf = (uint8_t*)malloc(fileSz); + if (*buf == NULL) + ret = MEMORY_E; + } + else if (*buf != NULL && fileSz > (ssize_t)*bufLen) { + ret = BUFFER_E; + } + *bufLen = (size_t)fileSz; + if (ret == 0) { + readLen = XFREAD(*buf, 1, *bufLen, fp); + ret = (readLen == (ssize_t)*bufLen) ? 0 : -1; + } + } + else { + ret = BUFFER_E; + } + XFCLOSE(fp); + return ret; +} + +static int writefile(const char* filename, const uint8_t *buf, size_t bufSz) +{ + int rc = -1; + XFILE fp; + size_t fileSz = 0; + + if (filename == NULL || buf == NULL) + return BAD_FUNC_ARG; + + fp = XFOPEN(filename, "wb"); + if (fp != XBADFILE) { + fileSz = XFWRITE(buf, 1, bufSz, fp); + /* sanity check */ + if (fileSz == bufSz) { + rc = 0; + } + printf("Wrote %d bytes to %s\n", (int)fileSz, filename); + XFCLOSE(fp); + } + + return rc; +} + +int main(int argc, char **argv) +{ + int rc; + uint8_t *manifest = NULL, *data = NULL, *fw = NULL; + size_t manifest_size, data_size, fw_size; + uint32_t keygroup_id = 0; + + if (argc <= 1 || + strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || + strcmp(argv[argc-1], "-h") == 0 || strcmp(argv[argc-1], "--help") == 0) + { + printf("Usage:\n"); + printf(" ifx_fw_extract \n"); + printf(" ifx_fw_extract \n"); + exit(1); + } + + if (argc >= 2) { + if (readfile(argv[1], &fw, &fw_size) < 0) { + LOG("Cannot read FW file."); + rc = EXIT_FAILURE; + goto exit; + } + + if (argc >= 3) { + if (sscanf(argv[2], "0x%08x", &keygroup_id) != 1 && sscanf(argv[2], "%08x", &keygroup_id) != 1) { + LOG("Cannot read keygroup_id."); + rc = EXIT_FAILURE; + goto exit; + } + } + rc = extractFW(fw, fw_size, keygroup_id, + &manifest, &manifest_size, + &data, &data_size); + if (rc != 0) { + printf(__FILE__":%i: Received error 0x%08x\n", __LINE__, rc); + goto exit; + } + + if (argc >= 5) { + if (writefile(argv[3], manifest, manifest_size) < 0) { + rc = EXIT_FAILURE; + goto exit; + } + if (writefile(argv[4], data, data_size) < 0) { + rc = EXIT_FAILURE; + goto exit; + } + } + rc = 0; + } + else { + printf("Bad arguments.\n"); + rc = EXIT_FAILURE; + goto exit; + } + +exit: + if (fw != NULL) + free(fw); + return rc; +} diff --git a/examples/firmware/ifx_fw_update.c b/examples/firmware/ifx_fw_update.c new file mode 100644 index 0000000..35d35bf --- /dev/null +++ b/examples/firmware/ifx_fw_update.c @@ -0,0 +1,235 @@ +/* ifx_fw_update.c + * + * Copyright (C) 2006-2024 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 2 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 + */ + +/* This tool will perform a firmware update on Infineon SLB9672 or SLB9673 + * TPM 2.0 module */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFTPM_FIRMWARE_UPGRADE + +#include +#include +#include + +/******************************************************************************/ +/* --- BEGIN TPM2.0 Firmware Update tool -- */ +/******************************************************************************/ + +static void usage(void) +{ + printf("Infineon Firmware Update Usage:\n"); + printf("\t./ifx_fw_update (get info)\n"); + printf("\t./ifx_fw_update --abandon (cancel)\n"); + printf("\t./ifx_fw_update \n"); +} + +typedef struct { + byte* manifest_buf; + byte* firmware_buf; + size_t manifest_bufSz; + size_t firmware_bufSz; +} fw_info_t; + +static int TPM2_IFX_FwData_Cb(uint8_t* data, uint32_t data_req_sz, + uint32_t offset, void* cb_ctx) +{ + fw_info_t* fwinfo = (fw_info_t*)cb_ctx; + if (offset > fwinfo->firmware_bufSz) { + return BUFFER_E; + } + if (offset + data_req_sz > (uint32_t)fwinfo->firmware_bufSz) { + data_req_sz = (uint32_t)fwinfo->firmware_bufSz - offset; + } + if (data_req_sz > 0) { + XMEMCPY(data, &fwinfo->firmware_buf[offset], data_req_sz); + } + return data_req_sz; +} + +static const char* TPM2_IFX_GetOpModeStr(int opMode) +{ + const char* opModeStr = "Unknown"; + switch (opMode) { + case 0x00: + opModeStr = "Normal TPM operational mode"; + break; + case 0x01: + opModeStr = "TPM firmware update mode (abandon possible)"; + break; + case 0x02: + opModeStr = "TPM firmware update mode (abandon not possible)"; + break; + case 0x03: + opModeStr = "After successful update, but before finalize"; + break; + case 0x04: + opModeStr = "After finalize or abandon, reboot required"; + break; + default: + break; + } + return opModeStr; +} + +static int TPM2_IFX_PrintInfo(WOLFTPM2_DEV* dev) +{ + int rc; + WOLFTPM2_CAPS caps; + rc = wolfTPM2_GetCapabilities(dev, &caps); + if (rc == TPM_RC_SUCCESS) { + printf("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x)\n", + caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor, + caps.fwVerMinor, caps.fwVerVendor); + printf("Operational mode: %s (0x%x)\n", + TPM2_IFX_GetOpModeStr(caps.opMode), caps.opMode); + printf("KeyGroupId 0x%x, FwCounter %d (%d same)\n", + caps.keyGroupId, caps.fwCounter, caps.fwCounterSame); + if (caps.keyGroupId == 0) { + printf("Error getting key group id from TPM!\n"); + rc = -1; + } + } + return rc; +} + +int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + const char* manifest_file = NULL; + const char* firmware_file = NULL; + fw_info_t fwinfo; + int abandon = 0; + + XMEMSET(&fwinfo, 0, sizeof(fwinfo)); + + if (argc >= 2) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + if (XSTRCMP(argv[1], "--abandon") == 0) { + abandon = 1; + } + else { + manifest_file = argv[1]; + if (argc >= 3) { + firmware_file = argv[2]; + } + } + } + + printf("Infineon Firmware Update Tool\n"); + if (manifest_file != NULL) + printf("\tManifest File: %s\n", manifest_file); + if (firmware_file != NULL) + printf("\tFirmware File: %s\n", firmware_file); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != TPM_RC_SUCCESS) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + goto exit; + } + + rc = TPM2_IFX_PrintInfo(&dev); + if (rc != 0) { + goto exit; + } + + if (abandon) { + printf("Firmware Update Abandon:\n"); + rc = wolfTPM2_FirmwareUpgradeCancel(&dev); + if (rc != 0) { + printf("Abandon failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + } + else { + printf("Success: Please reset or power cycle TPM\n"); + } + return rc; + } + + if (manifest_file == NULL || firmware_file == NULL) { + if (argc > 1) { + printf("Manifest file or firmware file arguments missing!\n"); + } + goto exit; + } + + /* load manifest and data files */ + rc = loadFile(manifest_file, + &fwinfo.manifest_buf, &fwinfo.manifest_bufSz); + if (rc == 0) { + rc = loadFile(firmware_file, + &fwinfo.firmware_buf, &fwinfo.firmware_bufSz); + } + if (rc == 0) { + rc = wolfTPM2_FirmwareUpgrade(&dev, + fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, + TPM2_IFX_FwData_Cb, &fwinfo); + } + if (rc == 0) { + rc = TPM2_IFX_PrintInfo(&dev); + } + +exit: + + if (rc != 0) { + printf("Infineon firmware update failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } + + XFREE(fwinfo.firmware_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(fwinfo.manifest_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2.0 Firmware Update tool -- */ +/******************************************************************************/ + +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char *argv[]) +{ + int rc = -1; + +#ifdef WOLFTPM_FIRMWARE_UPGRADE + rc = TPM2_IFX_Firmware_Update(NULL, argc, argv); +#else + printf("Support for firmware upgrade not compiled in! " + "See --enable-firmware or WOLFTPM_FIRMWARE_UPGRADE\n"); + (void)argc; + (void)argv; +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + + return rc; +} +#endif diff --git a/examples/firmware/ifx_fw_update.h b/examples/firmware/ifx_fw_update.h new file mode 100644 index 0000000..34d9fa5 --- /dev/null +++ b/examples/firmware/ifx_fw_update.h @@ -0,0 +1,35 @@ +/* ifx_firmware_update.h + * + * Copyright (C) 2006-2024 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 2 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 + */ + +#ifndef _IFX_FIRMWARE_H_ +#define _IFX_FIRMWARE_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* _IFX_FIRMWARE_H_ */ diff --git a/examples/firmware/include.am b/examples/firmware/include.am new file mode 100644 index 0000000..f233fe4 --- /dev/null +++ b/examples/firmware/include.am @@ -0,0 +1,24 @@ +# vim:ft=automake +# All paths should be given relative to the root + +EXTRA_DIST += examples/firmware/README.md +EXTRA_DIST += examples/firmware/Makefile + +# Host side tool for extracting the firmware manifest and data +EXTRA_DIST += examples/firmware/ifx_fw_extract.c + +if BUILD_EXAMPLES +if BUILD_INFINEON +noinst_PROGRAMS += examples/firmware/ifx_fw_update +noinst_HEADERS += examples/firmware/ifx_fw_update.h +examples_firmware_ifx_fw_update_SOURCES = examples/firmware/ifx_fw_update.c \ + examples/tpm_test_keys.c +examples_firmware_ifx_fw_update_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_firmware_ifx_fw_update_DEPENDENCIES = src/libwolftpm.la +endif +endif + +example_firmwaredir = $(exampledir)/firmware +dist_example_firmware_DATA = examples/firmware/ifx_fw_update.c + +DISTCLEANFILES+= examples/firmware/.libs/ifx_fw_update diff --git a/examples/include.am b/examples/include.am index 421fa33..2599321 100644 --- a/examples/include.am +++ b/examples/include.am @@ -16,6 +16,7 @@ include examples/nvram/include.am include examples/gpio/include.am include examples/seal/include.am include examples/attestation/include.am +include examples/firmware/include.am if BUILD_EXAMPLES EXTRA_DIST += examples/run_examples.sh diff --git a/examples/wrap/wrap_test.c b/examples/wrap/wrap_test.c index 4504a61..ddf8377 100644 --- a/examples/wrap/wrap_test.c +++ b/examples/wrap/wrap_test.c @@ -198,6 +198,10 @@ int TPM2_Wrapper_TestArgs(void* userCtx, int argc, char *argv[]) "FIPS 140-2 %d, CC-EAL4 %d\n", caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor, caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4); +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + printf("\tKeyGroupId 0x%x, Operational Mode 0x%x, FwCounter %d (%d same)\n", + caps.keyGroupId, caps.opMode, caps.fwCounter, caps.fwCounterSame); +#endif /* List the active persistent handles */ rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL); diff --git a/hal/tpm_io.c b/hal/tpm_io.c index d6faba1..f132430 100644 --- a/hal/tpm_io.c +++ b/hal/tpm_io.c @@ -65,7 +65,7 @@ #include "hal/tpm_io_qnx.c" #elif defined(__XILINX__) #include "hal/tpm_io_xilinx.c" -#elif defined(WOLFTPM_INFINEON_TRICORE) +#elif defined(WOLFTPM_INFINEON_TRICORE) || defined(CY_USING_HAL) #include "hal/tpm_io_infineon.c" #elif defined(WOLFTPM_MICROCHIP_HARMONY) #include "hal/tpm_io_microchip.c" @@ -89,6 +89,8 @@ static int TPM2_IoCb_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, ret = TPM2_IoCb_QNX_SPI(ctx, txBuf, rxBuf, xferSz, userCtx); #elif defined(__XILINX__) ret = TPM2_IoCb_Xilinx_SPI(ctx, txBuf, rxBuf, xferSz, userCtx); +#elif defined(CY_USING_HAL) + ret = TPM2_IoCb_Infineon_SPI(ctx, txBuf, rxBuf, xferSz, userCtx); #elif defined(WOLFTPM_INFINEON_TRICORE) ret = TPM2_IoCb_Infineon_TriCore_SPI(ctx, txBuf, rxBuf, xferSz, userCtx); #elif defined(WOLFTPM_MICROCHIP_HARMONY) @@ -140,6 +142,8 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr, #elif defined(WOLFSSL_STM32_CUBEMX) /* Use STM32 CubeMX HAL for I2C */ ret = TPM2_IoCb_STCubeMX_I2C(ctx, isRead, addr, buf, size, userCtx); + #elif defined(CY_USING_HAL) + ret = TPM2_IoCb_Infineon_I2C(ctx, isRead, addr, buf, size, userCtx); #else /* TODO: Add your platform here for HW I2C interface */ printf("Add your platform here for HW I2C interface\n"); diff --git a/hal/tpm_io.h b/hal/tpm_io.h index 402412b..371782a 100644 --- a/hal/tpm_io.h +++ b/hal/tpm_io.h @@ -82,6 +82,9 @@ WOLFTPM_LOCAL int TPM2_IoCb_Linux_I2C(TPM2_CTX* ctx, int isRead, word32 addr, by #elif defined(WOLFSSL_STM32_CUBEMX) WOLFTPM_LOCAL int TPM2_IoCb_STCubeMX_I2C(TPM2_CTX* ctx, int isRead, word32 addr, byte* buf, word16 size, void* userCtx); +#elif defined(CY_USING_HAL) +WOLFTPM_LOCAL int TPM2_IoCb_Infineon_I2C(TPM2_CTX* ctx, int isRead, word32 addr, + byte* buf, word16 size, void* userCtx); #endif /* __linux__ */ #else /* SPI */ @@ -104,6 +107,9 @@ WOLFTPM_LOCAL int TPM2_IoCb_QNX_SPI(TPM2_CTX* ctx, const byte* txBuf, #elif defined(__XILINX__) WOLFTPM_LOCAL int TPM2_IoCb_Xilinx_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, word16 xferSz, void* userCtx); +#elif defined(CY_USING_HAL) +WOLFTPM_LOCAL int TPM2_IoCb_Infineon_SPI(TPM2_CTX* ctx, const byte* txBuf, + byte* rxBuf, word16 xferSz, void* userCtx); #elif defined(WOLFTPM_INFINEON_TRICORE) WOLFTPM_LOCAL int TPM2_IoCb_Infineon_TriCore_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, word16 xferSz, void* userCtx); diff --git a/hal/tpm_io_infineon.c b/hal/tpm_io_infineon.c index 04bca15..6baa687 100644 --- a/hal/tpm_io_infineon.c +++ b/hal/tpm_io_infineon.c @@ -1,6 +1,6 @@ /* tpm_io_infineon.c * - * Copyright (C) 2006-2022 wolfSSL Inc. + * Copyright (C) 2006-2024 wolfSSL Inc. * * This file is part of wolfTPM. * @@ -19,7 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/* This example shows IO interfaces for Infineon TriCore hardware: +/* This example shows IO interfaces for Infineon CyHal or TriCore hardware: + * - PSoC6 CyHal set automatically with `CY_USING_HAL`. * - TC2XX/TC3XX using macro: `WOLFTPM_INFINEON_TRICORE`. */ @@ -42,12 +43,131 @@ defined(WOLFTPM_SWTPM) || \ defined(WOLFTPM_WINAPI) ) -/* Use the max speed by default - see tpm2_types.h for chip specific max values */ -#ifndef TPM2_SPI_HZ - #define TPM2_SPI_HZ TPM2_SPI_MAX_HZ -#endif +#ifdef WOLFTPM_I2C + #ifndef TPM_I2C_TRIES + #define TPM_I2C_TRIES 10 + #endif + #ifndef TPM2_I2C_ADDR + #define TPM2_I2C_ADDR 0x2e + #endif -#if defined(WOLFTPM_INFINEON_TRICORE) + #if defined(CY_USING_HAL) + #include "cyhal_i2c.h" + + static int tpm_ifx_i2c_read(void* userCtx, word32 reg, byte* data, int len) + { + int ret = TPM_RC_FAILURE; + cy_rslt_t result; + cyhal_i2c_t* i2c = (cyhal_i2c_t*)userCtx; + int timeout = TPM_I2C_TRIES; + byte buf[1]; + + /* TIS layer should never provide a buffer larger than this, + * but double check for good coding practice */ + if (i2c == NULL || len > MAX_SPI_FRAMESIZE) + return BAD_FUNC_ARG; + + buf[0] = (reg & 0xFF); /* convert to simple 8-bit address for I2C */ + + /* The I2C takes about 80us to wake up and will NAK until it is ready */ + do { + /* Write address to read from - retry until ack */ + result = cyhal_i2c_master_write(i2c, TPM2_I2C_ADDR, buf, sizeof(buf), + 0, true); + /* for read we always need this guard time (success wake or real read) */ + XSLEEP_MS(1); /* guard time - should be 250us */ + } while (result != CY_RSLT_SUCCESS && --timeout > 0); + + if (result == CY_RSLT_SUCCESS) { + timeout = TPM_I2C_TRIES; + do { + result = cyhal_i2c_master_read(i2c, TPM2_I2C_ADDR, data, len, + 0, true); + if (result != CY_RSLT_SUCCESS) { + XSLEEP_MS(1); /* guard time - should be 250us */ + } + } while (result != CY_RSLT_SUCCESS && --timeout > 0); + } + if (result == CY_RSLT_SUCCESS) { + ret = TPM_RC_SUCCESS; + } + else { + printf("CyHAL I2C Read failure %d (tries %d)\n", + (int)result, TPM_I2C_TRIES - timeout); + } + return ret; + } + + static int tpm_ifx_i2c_write(void* userCtx, word32 reg, byte* data, int len) + { + int ret = TPM_RC_FAILURE; + cy_rslt_t result; + cyhal_i2c_t* i2c = (cyhal_i2c_t*)userCtx; + int timeout = TPM_I2C_TRIES; + byte buf[MAX_SPI_FRAMESIZE+1]; + + /* TIS layer should never provide a buffer larger than this, + * but double check for good coding practice */ + if (i2c == NULL || len > MAX_SPI_FRAMESIZE) + return BAD_FUNC_ARG; + + /* Build packet with TPM register and data */ + buf[0] = (reg & 0xFF); /* convert to simple 8-bit address for I2C */ + XMEMCPY(buf + 1, data, len); + + /* The I2C takes about 80us to wake up and will NAK until it is ready */ + do { + result = cyhal_i2c_master_write(i2c, TPM2_I2C_ADDR, buf, len+1, + 0, true); + if (result != CY_RSLT_SUCCESS) { + XSLEEP_MS(1); /* guard time - should be 250us */ + } + } while (result != CY_RSLT_SUCCESS && --timeout > 0); + if (result == CY_RSLT_SUCCESS) { + ret = TPM_RC_SUCCESS; + } + else { + printf("CyHAL I2C Write failure %d\n", (int)result); + } + return ret; + } + + int TPM2_IoCb_Infineon_I2C(TPM2_CTX* ctx, int isRead, word32 addr, + byte* buf, word16 size, void* userCtx) + { + int ret = TPM_RC_FAILURE; + if (userCtx != NULL) { + if (isRead) + ret = tpm_ifx_i2c_read(userCtx, addr, buf, size); + else + ret = tpm_ifx_i2c_write(userCtx, addr, buf, size); + } + (void)ctx; + return ret; + } + + #else + #error Infineon I2C support on this platform not supported yet + #endif /* CY_USING_HAL or WOLFTPM_INFINEON_TRICORE */ + +#else /* SPI */ + + #ifndef TPM2_SPI_HZ + /* Use the max speed by default + * See tpm2_types.h for chip specific max values */ + #define TPM2_SPI_HZ TPM2_SPI_MAX_HZ + #endif + #ifdef WOLFTPM_CHECK_WAIT_STATE + #error SPI check wait state logic not supported + #endif + + #if defined(CY_USING_HAL) + int TPM2_IoCb_Infineon_SPI(TPM2_CTX* ctx, const byte* txBuf, + byte* rxBuf, word16 xferSz, void* userCtx) + { + + } + #elif defined(WOLFTPM_INFINEON_TRICORE) #include #include @@ -60,10 +180,6 @@ { int ret = TPM_RC_FAILURE; - #ifdef WOLFTPM_CHECK_WAIT_STATE - #error SPI check wait state logic not supported - #endif - /* wait for SPI not busy */ while (IfxQspi_SpiMaster_getStatus(&spiMasterChannel) == SpiIf_Status_busy) {}; @@ -79,8 +195,11 @@ return ret; } + #else + #error Infineon I2C support on this platform not supported yet + #endif /* CY_USING_HAL or WOLFTPM_INFINEON_TRICORE */ +#endif /* SPI or I2C */ -#endif /* WOLFTPM_INFINEON_TRICORE */ #endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */ #endif /* WOLFTPM_INCLUDE_IO_FILE */ diff --git a/hal/tpm_io_linux.c b/hal/tpm_io_linux.c index 193498d..8e340c6 100644 --- a/hal/tpm_io_linux.c +++ b/hal/tpm_io_linux.c @@ -65,7 +65,7 @@ #include #ifdef WOLFTPM_I2C - /* I2C - (Only tested with ST33HTPH I2C) */ + /* I2C - (Only tested with SLB9673 and ST33 I2C) */ #define TPM2_I2C_ADDR 0x2e #define TPM2_I2C_DEV "/dev/i2c-1" #define TPM2_I2C_HZ 400000 /* 400kHz */ diff --git a/src/tpm2.c b/src/tpm2.c index 883fea7..89f6b13 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -575,7 +575,7 @@ TPM_RC TPM2_SetHalIoCb(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx) } /* If timeoutTries <= 0 then it will not try and startup chip and will - use existing default locality */ + * use existing default locality */ TPM_RC TPM2_Init_ex(TPM2_CTX* ctx, TPM2HalIoCb ioCb, void* userCtx, int timeoutTries) { @@ -870,6 +870,20 @@ TPM_RC TPM2_GetCapability(GetCapability_In* in, GetCapability_Out* out) } break; } + case TPM_CAP_VENDOR_PROPERTY: + { + out->capabilityData.data.vendor.size = + packet.size - packet.pos; + if (out->capabilityData.data.vendor.size > + sizeof(out->capabilityData.data.vendor.buffer)) { + out->capabilityData.data.vendor.size = + sizeof(out->capabilityData.data.vendor.buffer); + } + TPM2_Packet_ParseBytes(&packet, + out->capabilityData.data.vendor.buffer, + out->capabilityData.data.vendor.size); + break; + } default: #ifdef DEBUG_WOLFTPM printf("Unknown capability type 0x%x\n", @@ -5394,6 +5408,63 @@ int TPM2_NTC2_GetConfig(NTC2_GetConfig_Out* out) return rc; } #endif /* WOLFTPM_NUVOTON */ + + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +int TPM2_IFX_FieldUpgradeStart(TPM_HANDLE sessionHandle, + uint8_t* data, uint32_t size) +{ + int rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + TPMS_AUTH_COMMAND session; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + int tmpSz = 0; + TPM2_Packet_Init(ctx, &packet); + TPM2_Packet_AppendU32(&packet, TPM_RH_PLATFORM); + + XMEMSET(&session, 0, sizeof(session)); + session.sessionHandle = sessionHandle; + + TPM2_Packet_MarkU32(&packet, &tmpSz); + TPM2_Packet_AppendAuthCmd(&packet, &session); + TPM2_Packet_PlaceU32(&packet, tmpSz); + + TPM2_Packet_AppendBytes(&packet, data, size); + + TPM2_Packet_Finalize(&packet, TPM_ST_SESSIONS, + TPM_CC_FieldUpgradeStartVendor); + + rc = TPM2_SendCommand(ctx, &packet); + + TPM2_ReleaseLock(ctx); + } + return rc; +} +int TPM2_IFX_FieldUpgradeCommand(TPM_CC cc, uint8_t* data, uint32_t size) +{ + int rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + TPM2_Packet_Init(ctx, &packet); + TPM2_Packet_AppendBytes(&packet, data, size); + TPM2_Packet_Finalize(&packet, TPM_ST_NO_SESSIONS, cc); + rc = TPM2_SendCommand(ctx, &packet); + TPM2_ReleaseLock(ctx); + } + return rc; +} + + +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + /******************************************************************************/ /* --- END Manufacture Specific TPM API's -- */ /******************************************************************************/ diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index 0cb830e..e7f687f 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -25,23 +25,6 @@ #include -/* Endianess Helpers */ -#ifdef LITTLE_ENDIAN_ORDER - #define cpu_to_be16(d) ByteReverseWord16(d) - #define cpu_to_be32(d) ByteReverseWord32(d) - #define cpu_to_be64(d) ByteReverseWord64(d) - #define be16_to_cpu(d) ByteReverseWord16(d) - #define be32_to_cpu(d) ByteReverseWord32(d) - #define be64_to_cpu(d) ByteReverseWord64(d) -#else - #define cpu_to_be16(d) (d) - #define cpu_to_be32(d) (d) - #define cpu_to_be64(d) (d) - #define be16_to_cpu(d) (d) - #define be32_to_cpu(d) (d) - #define be64_to_cpu(d) (d) -#endif - /* convert 16 bit integer to opaque */ static inline void c16toa(word16 wc_u16, byte* c) { diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ce9e398..2996367 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -619,6 +619,15 @@ int wolfTPM2_SelfTest(WOLFTPM2_DEV* dev) * TPM_PT_MODES = Bit 0 = FIPS_140_2 */ +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + /* Infineon SLB9672 or SLB9673 Firmware Upgrade support */ + #define TPM_PT_VENDOR_FIX 0x80000000 + #define TPM_PT_VENDOR_FIX_FU_COUNTER (TPM_PT_VENDOR_FIX + 3) + #define TPM_PT_VENDOR_FIX_FU_COUNTER_SAME (TPM_PT_VENDOR_FIX + 4) + #define TPM_PT_VENDOR_FIX_FU_OPERATION_MODE (TPM_PT_VENDOR_FIX + 7) + #define TPM_PT_VENDOR_FIX_FU_KEYGROUP_ID (TPM_PT_VENDOR_FIX + 8) +#endif + /* ST33TP * TPM_PT_MANUFACTURER 0x53544D20: "STM" * TPM_PT_FIRMWARE_VERSION_1 TPM FW version: 0x00006400 @@ -698,6 +707,44 @@ static int wolfTPM2_ParseCapabilities(WOLFTPM2_CAPS* caps, return rc; } +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) +static int tpm2_ifx_cap_vendor_get(WOLFTPM2_CAPS* cap, uint32_t property, + uint8_t* val, size_t valSz) +{ + int rc; + GetCapability_In in; + GetCapability_Out out; + + XMEMSET(&in, 0, sizeof(in)); + XMEMSET(&out, 0, sizeof(out)); + in.capability = TPM_CAP_VENDOR_PROPERTY; + in.property = property; + in.propertyCount = 1; + rc = TPM2_GetCapability(&in, &out); + if (rc == TPM_RC_SUCCESS) { + TPM2B_MAX_BUFFER* buf = &out.capabilityData.data.vendor; + /* 4 bytes=count + 2 bytes=len + vendor value */ + if (buf->buffer[3] == 1 && buf->buffer[5] == valSz) { + XMEMCPY(val, &buf->buffer[6], valSz); + if (valSz == 2) { + *((uint16_t*)val) = be16_to_cpu(*((uint16_t*)val)); + } + else if (valSz == 4) { + *((uint32_t*)val) = be32_to_cpu(*((uint32_t*)val)); + } + } + } + else { + #ifdef DEBUG_WOLFTPM + printf("TPM2_GetCapability vendor prop 0x%x failed 0x%x: %s\n", + property, rc, TPM2_GetRCString(rc)); + #endif + } + (void)cap; + return rc; +} +#endif + static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap) { int rc; @@ -712,14 +759,15 @@ static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap) /* Get Capabilities TPM_PT_MANUFACTURER thru TPM_PT_FIRMWARE_VERSION_2 */ XMEMSET(&in, 0, sizeof(in)); + XMEMSET(&out, 0, sizeof(out)); in.capability = TPM_CAP_TPM_PROPERTIES; in.property = TPM_PT_MANUFACTURER; in.propertyCount = 8; rc = TPM2_GetCapability(&in, &out); if (rc != TPM_RC_SUCCESS) { #ifdef DEBUG_WOLFTPM - printf("TPM2_GetCapability failed 0x%x: %s\n", rc, - TPM2_GetRCString(rc)); + printf("TPM2_GetCapability manufacture failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); #endif return rc; } @@ -729,19 +777,40 @@ static int wolfTPM2_GetCapabilities_NoDev(WOLFTPM2_CAPS* cap) /* Get Capability TPM_PT_MODES */ XMEMSET(&in, 0, sizeof(in)); + XMEMSET(&out, 0, sizeof(out)); in.capability = TPM_CAP_TPM_PROPERTIES; in.property = TPM_PT_MODES; in.propertyCount = 1; rc = TPM2_GetCapability(&in, &out); if (rc != TPM_RC_SUCCESS) { #ifdef DEBUG_WOLFTPM - printf("TPM2_GetCapability failed 0x%x: %s\n", rc, - TPM2_GetRCString(rc)); + printf("TPM2_GetCapability modes failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); #endif return rc; } rc = wolfTPM2_ParseCapabilities(cap, &out.capabilityData.data.tpmProperties); +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + /* Get vendor specific information */ + if (rc == 0) { + rc = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_OPERATION_MODE, + &cap->opMode, sizeof(cap->opMode)); + } + if (rc == 0) { + rc = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_KEYGROUP_ID, + (uint8_t*)&cap->keyGroupId, sizeof(cap->keyGroupId)); + } + if (rc == 0) { + rc = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_COUNTER, + (uint8_t*)&cap->fwCounter, sizeof(cap->fwCounter)); + } + if (rc == 0) { + rc = tpm2_ifx_cap_vendor_get(cap, TPM_PT_VENDOR_FIX_FU_COUNTER_SAME, + (uint8_t*)&cap->fwCounterSame, sizeof(cap->fwCounterSame)); + } +#endif + return rc; } @@ -1144,7 +1213,7 @@ static int wolfTPM2_EncryptSecret_ECC(WOLFTPM2_DEV* dev, const WOLFTPM2_KEY* tpm TPM2B_ECC_POINT pubPoint, secretPoint; ecc_point r[1]; mp_int prime, a; - word32 keySz; + word32 keySz = 0; publicArea = &tpmKey->pub.publicArea; XMEMSET(&rng, 0, sizeof(rng)); @@ -4454,7 +4523,7 @@ int wolfTPM2_NVReadCert(WOLFTPM2_DEV* dev, TPM_HANDLE handle, /* Perform read of NV without auth password */ nv.handle.hndl = handle; - rc = wolfTPM2_NVReadAuth(dev, &nv, handle, buffer, len, 0); + rc = wolfTPM2_NVReadAuth(dev, &nv, handle, buffer, (word32*)len, 0); return rc; } @@ -7123,4 +7192,323 @@ int wolfTPM2_SetIdentityAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle, + +/******************************************************************************/ +/* --- BEGIN Firmware Upgrade Support -- */ +/******************************************************************************/ + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + +/* Maximum size of firmware chunks */ +#define IFX_FW_MAX_CHUNK_SZ 1024 + +/* Setup the policy to enable firmware upgrade start */ +static int tpm2_ifx_firmware_enable_policy(WOLFTPM2_DEV* dev) +{ + int rc; + PolicyCommandCode_In policyCC; + SetPrimaryPolicy_In policy; + WOLFTPM2_SESSION tpmSession; + + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); + XMEMSET(&policyCC, 0, sizeof(policyCC)); + XMEMSET(&policy, 0, sizeof(policy)); + + rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + if (rc == TPM_RC_SUCCESS) { + policyCC.policySession = tpmSession.handle.hndl; + policyCC.code = TPM_CC_FieldUpgradeStartVendor; + rc = TPM2_PolicyCommandCode(&policyCC); + if (rc == TPM_RC_SUCCESS) { + word32 policySz = (word32)sizeof(policy.authPolicy.buffer); + rc = wolfTPM2_GetPolicyDigest(dev, tpmSession.handle.hndl, + policy.authPolicy.buffer, &policySz); + policy.authPolicy.size = policySz; + } + wolfTPM2_UnloadHandle(dev, &tpmSession.handle); + } + if (rc == TPM_RC_SUCCESS) { + policy.authHandle = TPM_RH_PLATFORM; + policy.hashAlg = TPM_ALG_SHA256; + rc = TPM2_SetPrimaryPolicy(&policy); + } + +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Enable firmware start policy failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +static int tpm2_ifx_firmware_start(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, + uint8_t* manifest_hash, uint32_t manifest_hash_sz) +{ + int rc; + WOLFTPM2_SESSION tpmSession; + PolicyCommandCode_In policyCC; + + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); + XMEMSET(&policyCC, 0, sizeof(policyCC)); + + rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + if (rc == TPM_RC_SUCCESS) { + policyCC.policySession = tpmSession.handle.hndl; + policyCC.code = TPM_CC_FieldUpgradeStartVendor; + rc = TPM2_PolicyCommandCode(&policyCC); + if (rc == TPM_RC_SUCCESS) { + /* build command for manifest header */ + uint16_t val16; + /* max cmd: type (1) + data sz (2) + hash alg (2) + max digest (64) */ + uint8_t cmd[1 + 2 + 2 + TPM_SHA512_DIGEST_SIZE]; + cmd[0] = 0x01; /* type */ + val16 = be16_to_cpu(manifest_hash_sz + 2); + XMEMCPY(&cmd[1], &val16, sizeof(val16)); /* data size */ + val16 = be16_to_cpu(hashAlg); + XMEMCPY(&cmd[3], &val16, sizeof(val16)); /* hash algorithm */ + XMEMCPY(&cmd[5], manifest_hash, manifest_hash_sz); + + rc = TPM2_IFX_FieldUpgradeStart(tpmSession.handle.hndl, + cmd, 1 + 2 + 2 + manifest_hash_sz); + } + if (rc == TPM_RC_SUCCESS) { + /* delay to give the TPM time to switch modes */ + XSLEEP_MS(300); + /* it is not required to release session handle, + * since TPM reset into firmware upgrade mode */ + + #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \ + !defined(WOLFTPM_WINAPI) + /* Do chip startup and request locality again */ + rc = TPM2_ChipStartup(&dev->ctx, 10); + #endif + } + else { + wolfTPM2_UnloadHandle(dev, &tpmSession.handle); + } + } +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Firmware upgrade start failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +static int tpm2_ifx_firmware_manifest(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz) +{ + int rc = TPM_RC_FAILURE; + uint32_t offset, chunk_sz; + uint8_t state; /* 1=start, 2=more, 0=done */ + + (void)dev; + for (offset = 0; offset < manifest_sz; offset += chunk_sz) { + /* max cmd: type (1) + chunk sz (2) + max chunk (1024) */ + uint8_t cmd[1 + 2 + IFX_FW_MAX_CHUNK_SZ]; + uint16_t val16; + + chunk_sz = manifest_sz - offset; + if (chunk_sz > IFX_FW_MAX_CHUNK_SZ) { + chunk_sz = IFX_FW_MAX_CHUNK_SZ; + state = (offset == 0) ? 1 : 2; + } + else { + state = 0; + } + #ifdef DEBUG_WOLFTPM + printf("Firmware manifest chunk %u offset (%u / %u), state %d\n", + chunk_sz, offset, manifest_sz, state); + #endif + + cmd[0] = state; + val16 = be16_to_cpu(chunk_sz); + XMEMCPY(&cmd[1], &val16, sizeof(val16)); /* chunk size */ + XMEMCPY(&cmd[3], &manifest[offset], chunk_sz); + + rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeManifestVendor, + cmd, 1 + 2 + chunk_sz); + if (rc != TPM_RC_SUCCESS) { + break; + } + } +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Firmware upgrade manifest failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +static int tpm2_ifx_firmware_data(WOLFTPM2_DEV* dev, + wolfTPM2FwDataCb cb, void* cb_ctx) +{ + int rc; + uint32_t offset, chunk_sz; + uint8_t cmd[2 + IFX_FW_MAX_CHUNK_SZ]; + uint16_t val16; + + (void)dev; + for (offset = 0; ; offset += chunk_sz) { + XMEMSET(cmd, 0, sizeof(cmd)); + + /* get chunk */ + rc = cb(&cmd[2], IFX_FW_MAX_CHUNK_SZ, offset, cb_ctx); + if (rc > 0 && rc <= IFX_FW_MAX_CHUNK_SZ) { + chunk_sz = rc; + rc = 0; + } + else if (rc == 0) { + #ifdef DEBUG_WOLFTPM + printf("Firmware data done\n"); + #endif + break; + } + else { + #ifdef DEBUG_WOLFTPM + printf("Firmware data callback error! %d\n", rc); + #endif + break; + } + + #ifdef DEBUG_WOLFTPM + printf("Firmware data chunk offset %u\n", offset); + #endif + + val16 = be16_to_cpu(chunk_sz); + XMEMCPY(&cmd[0], &val16, sizeof(val16)); /* chunk size */ + + rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeDataVendor, + cmd, 2 + chunk_sz); + if (rc != TPM_RC_SUCCESS) { + break; + } + } + + if (rc == TPM_RC_SUCCESS) { + /* Give the TPM time to start the new firmware */ + XSLEEP_MS(300); + + #if !defined(WOLFTPM_LINUX_DEV) && !defined(WOLFTPM_SWTPM) && \ + !defined(WOLFTPM_WINAPI) + /* Do chip startup and request locality again */ + rc = TPM2_ChipStartup(&dev->ctx, 10); + #endif + } +#ifdef DEBUG_WOLFTPM + else { + printf("Firmware upgrade data failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +static int tpm2_ifx_firmware_final(WOLFTPM2_DEV* dev) +{ + int rc; + uint8_t cmd[2]; + uint16_t val16; + + (void)dev; + + val16 = 0; + XMEMCPY(&cmd[0], &val16, sizeof(val16)); /* data size */ + + rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeFinalizeVendor, + cmd, sizeof(cmd)); +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Firmware finalize failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx) +{ + int rc; + WOLFTPM2_CAPS caps; + TPM_ALG_ID hashAlg; + uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE]; + uint32_t manifest_hash_sz = (uint32_t)sizeof(manifest_hash); + + /* check the operational mode */ + rc = wolfTPM2_GetCapabilities(dev, &caps); + if (rc == TPM_RC_SUCCESS) { + if (caps.opMode == 0x03) { + /* firmware update is done, just needs finalized and TPM reset */ + #ifdef DEBUG_WOLFTPM + printf("Firmware update done, finalizing\n"); + #endif + return tpm2_ifx_firmware_final(dev); + } + } + + /* hash the manifest */ + hashAlg = TPM_ALG_SHA384; /* use SHA2-384 or SHA2-512 for manifest hash */ + rc = wc_Sha384Hash(manifest, manifest_sz, manifest_hash); + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ifx_firmware_enable_policy(dev); + } + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ifx_firmware_start(dev, hashAlg, manifest_hash, manifest_hash_sz); + } + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ifx_firmware_manifest(dev, manifest, manifest_sz); + } + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ifx_firmware_data(dev, cb, cb_ctx); + } + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ifx_firmware_final(dev); + } +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Firmware update failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +/* terminate a firmware update */ +int wolfTPM2_FirmwareUpgradeCancel(WOLFTPM2_DEV* dev) +{ + int rc; + uint8_t cmd[2]; + uint16_t val16; + + (void)dev; + + val16 = 0; /* data size */ + XMEMCPY(&cmd[0], &val16, sizeof(val16)); + + rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor, + cmd, sizeof(cmd)); +#ifdef DEBUG_WOLFTPM + if (rc != TPM_RC_SUCCESS) { + printf("Firmware abandon failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } +#endif + return rc; +} + +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */ +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + +/******************************************************************************/ +/* --- END Firmware Upgrade Support -- */ +/******************************************************************************/ + #endif /* !WOLFTPM2_NO_WRAPPER */ diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index 39389ae..5dd01cd 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -261,6 +261,13 @@ typedef enum { TPM_CC_NTC2_PreConfig = CC_VEND + 0x0211, TPM_CC_NTC2_GetConfig = CC_VEND + 0x0213, #endif +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + TPM_CC_FieldUpgradeStartVendor = CC_VEND + 0x12F, + TPM_CC_FieldUpgradeAbandonVendor = CC_VEND + 0x130, + TPM_CC_FieldUpgradeManifestVendor = CC_VEND + 0x131, + TPM_CC_FieldUpgradeDataVendor = CC_VEND + 0x132, + TPM_CC_FieldUpgradeFinalizeVendor = CC_VEND + 0x133, +#endif } TPM_CC_T; typedef UINT32 TPM_CC; @@ -1017,6 +1024,7 @@ typedef union TPMU_CAPABILITIES { TPML_TAGGED_PCR_PROPERTY pcrProperties; /* TPM_CAP_PCR_PROPERTIES */ TPML_ECC_CURVE eccCurves; /* TPM_CAP_ECC_CURVES */ TPML_TAGGED_POLICY authPolicies; /* TPM_CAP_AUTH_POLICIES */ + TPM2B_MAX_BUFFER vendor; } TPMU_CAPABILITIES; typedef struct TPMS_CAPABILITY_DATA { @@ -2823,7 +2831,20 @@ WOLFTPM_API TPM_RC TPM2_NV_Certify(NV_Certify_In* in, NV_Certify_Out* out); WOLFTPM_API TPM_RC TPM2_GetRandom2(GetRandom2_In* in, GetRandom2_Out* out); WOLFTPM_API TPM_RC TPM2_GetProductInfo(uint8_t* info, uint16_t size); -#endif +#endif /* ST33 Vendor Specific */ + + +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) || \ + defined(WOLFTPM_AUTODETECT) + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +WOLFTPM_API int TPM2_IFX_FieldUpgradeStart(TPM_HANDLE sessionHandle, + uint8_t* data, uint32_t size); +WOLFTPM_API int TPM2_IFX_FieldUpgradeCommand(TPM_CC cc, uint8_t* data, uint32_t size); +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + +#endif /* Infineon SLB Vendor Specific */ + /* Vendor Specific GPIO */ #ifdef WOLFTPM_ST33 @@ -2959,8 +2980,7 @@ WOLFTPM_API TPM_RC TPM2_NV_Certify(NV_Certify_In* in, NV_Certify_Out* out); CFG_STRUCT preConfig; } NTC2_GetConfig_Out; WOLFTPM_API int TPM2_NTC2_GetConfig(NTC2_GetConfig_Out* out); - -#endif /* WOLFTPM_ST33 || WOLFTPM_AUTODETECT */ +#endif /* Vendor GPIO Commands */ /* Non-standard API's */ diff --git a/wolftpm/tpm2_packet.h b/wolftpm/tpm2_packet.h index 76ac00a..fa9da7f 100644 --- a/wolftpm/tpm2_packet.h +++ b/wolftpm/tpm2_packet.h @@ -30,6 +30,23 @@ #define TPM2_HEADER_SIZE 10 /* expected TPM2 header size */ +/* Endianess Helpers */ +#ifdef LITTLE_ENDIAN_ORDER + #define cpu_to_be16(d) ByteReverseWord16(d) + #define cpu_to_be32(d) ByteReverseWord32(d) + #define cpu_to_be64(d) ByteReverseWord64(d) + #define be16_to_cpu(d) ByteReverseWord16(d) + #define be32_to_cpu(d) ByteReverseWord32(d) + #define be64_to_cpu(d) ByteReverseWord64(d) +#else + #define cpu_to_be16(d) (d) + #define cpu_to_be32(d) (d) + #define cpu_to_be64(d) (d) + #define be16_to_cpu(d) (d) + #define be32_to_cpu(d) (d) + #define be64_to_cpu(d) (d) +#endif + /* For reference here is the TPM2 header (not used) */ typedef struct TPM2_HEADER { UINT16 tag; diff --git a/wolftpm/tpm2_types.h b/wolftpm/tpm2_types.h index aa81435..82333dd 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -308,13 +308,19 @@ typedef int64_t INT64; #define TPM2_SPI_MAX_HZ TPM2_SPI_MAX_HZ_NUVOTON #endif #else - /* Infineon OPTIGA SLB9670/SLB9672 */ + /* Infineon OPTIGA SLB9670/SLB9672/SLB9673 */ #ifdef WOLFTPM_SLB9670 /* Max: 43MHz */ #define TPM2_SPI_MAX_HZ_INFINEON 43000000 - #else - #undef WOLFTPM_SLB9672 - #define WOLFTPM_SLB9672 + #elif !defined(WOLFTPM_AUTODETECT) + #ifdef WOLFTPM_I2C + #undef WOLFTPM_SLB9673 + #define WOLFTPM_SLB9673 + #else + #undef WOLFTPM_SLB9672 + #define WOLFTPM_SLB9672 + #endif + /* Max: 33MHz */ #define TPM2_SPI_MAX_HZ_INFINEON 33000000 #endif @@ -441,6 +447,29 @@ typedef int64_t INT64; #define XTPM_WAIT() /* just poll without delay by default */ #endif +/* sleep helper, used in firmware update */ +#ifndef XSLEEP_MS + #ifdef WIN32 + #include + #define XSLEEP_MS(ms) Sleep(ms) + #elif defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L + #include + #define XSLEEP_MS(ms) ({ \ + struct timespec ts; \ + ts.tv_sec = ms / 1000; \ + ts.tv_nsec = (ms % 1000) * 1000000; \ + nanosleep(&ts, NULL); \ + }) + #else + #include + #define XSLEEP_MS(ms) ({ \ + if (ms >= 1000) \ + sleep(ms / 1000); \ + usleep((ms % 1000) * 1000); \ + }) + #endif +#endif + #ifndef BUFFER_ALIGNMENT #define BUFFER_ALIGNMENT 4 #endif @@ -645,6 +674,15 @@ typedef int64_t INT64; #define WOLFTPM2_PEM_DECODE #endif +/* Firmware upgrade requires wolfCrypt for hash and supported + * only for Infineon SLB9672/SLB9673 */ +#if defined(WOLFTPM_FIRMWARE_UPGRADE) && \ + (defined(WOLFTPM2_NO_WOLFCRYPT) || \ + (!defined(WOLFTPM_SLB9672) && !defined(WOLFTPM_SLB9673))) + #undef WOLFTPM_FIRMWARE_UPGRADE +#endif + + /* ---------------------------------------------------------------------------*/ /* ENDIANESS HELPERS */ /* ---------------------------------------------------------------------------*/ diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 4f9cd78..4889a27 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -118,6 +118,12 @@ typedef struct WOLFTPM2_CAPS { word16 fwVerMajor; word16 fwVerMinor; word32 fwVerVendor; +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673) + word32 keyGroupId; + word16 fwCounter; + word16 fwCounterSame; + byte opMode; +#endif /* bits */ word16 fips140_2 : 1; /* using FIPS mode */ @@ -3567,6 +3573,18 @@ WOLFTPM_LOCAL int GetKeyTemplateECC(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash); + +#ifdef WOLFTPM_FIRMWARE_UPGRADE +typedef int (*wolfTPM2FwDataCb)( + uint8_t* data, uint32_t data_req_sz, uint32_t offset, void* cb_ctx); + +WOLFTPM_API int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx); +WOLFTPM_API int wolfTPM2_FirmwareUpgradeCancel(WOLFTPM2_DEV* dev); + +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ + #ifdef __cplusplus } /* extern "C" */ #endif