mirror of https://github.com/wolfSSL/wolfTPM.git
392 lines
14 KiB
C
392 lines
14 KiB
C
/* ifx_fw_update.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
|
|
*/
|
|
|
|
/* This tool will perform a firmware update on Infineon SLB9672 or SLB9673
|
|
* TPM 2.0 module */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolftpm/tpm2_wrap.h>
|
|
|
|
/* wolfTPM2_FirmwareUpgrade_ex hashes the manifest with SHA-384, so it is only
|
|
* built with wolfCrypt. This tool has no other way to drive an upgrade. */
|
|
#if defined(WOLFTPM_FIRMWARE_UPGRADE) && \
|
|
(defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)) && \
|
|
!defined(WOLFTPM2_NO_WOLFCRYPT)
|
|
|
|
#include <examples/firmware/ifx_fw_update.h>
|
|
#include <examples/firmware/firmware_policy.h>
|
|
#include <examples/tpm_test_keys.h>
|
|
#include <hal/tpm_io.h>
|
|
|
|
/* WOLFTPM_HAVE_FW_POLICY comes from firmware_policy.h, which owns the
|
|
* condition so the two firmware examples cannot drift. */
|
|
|
|
/* Caller-supplied policy authorization modes */
|
|
#define IFX_POLICY_NONE 0 /* library-managed authorization */
|
|
#define IFX_POLICY_CMDCODE 1 /* --policy: single PolicyCommandCode */
|
|
#define IFX_POLICY_OR 2 /* --policyor: multi-branch PolicyOR */
|
|
|
|
/* Infineon operational modes (subset used here) */
|
|
#define IFX_OPMODE_NORMAL 0x00 /* normal; FieldUpgradeStart reached */
|
|
#define IFX_OPMODE_RECOVERY 0x02 /* recovery; start is skipped */
|
|
#define IFX_OPMODE_FINALIZE 0x03 /* update done, finalize only */
|
|
|
|
/******************************************************************************/
|
|
/* --- 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 --policytest (safe policy auth self-test)\n");
|
|
printf("\t./ifx_fw_update [policy opts] <manifest_file> <firmware_file>\n");
|
|
printf("\t./ifx_fw_update <manifest_file> <firmware_file> "
|
|
"(default auth)\n");
|
|
printf("Policy options (caller-supplied authorization):\n");
|
|
printf("\t--policy provision+satisfy a PolicyCommandCode\n");
|
|
printf("\t--policyor provision+satisfy a PolicyOR (multi-branch)\n");
|
|
printf("\t--sha256|--sha384|--sha512 policy hash (default SHA-256)\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 void TPM2_IFX_PrintInfo(WOLFTPM2_CAPS* caps)
|
|
{
|
|
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);
|
|
}
|
|
|
|
int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[])
|
|
{
|
|
int rc;
|
|
WOLFTPM2_DEV dev;
|
|
WOLFTPM2_CAPS caps;
|
|
const char* manifest_file = NULL;
|
|
const char* firmware_file = NULL;
|
|
fw_info_t fwinfo;
|
|
int abandon = 0, recovery = 0;
|
|
int i;
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
int policytest = 0;
|
|
int policyMode = IFX_POLICY_NONE;
|
|
TPMI_ALG_HASH policyHash = TPM_ALG_SHA256;
|
|
WOLFTPM2_SESSION policySession;
|
|
FirmwarePolicyCtx policyCtx;
|
|
int clearRc;
|
|
#endif
|
|
|
|
XMEMSET(&fwinfo, 0, sizeof(fwinfo));
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
XMEMSET(&policySession, 0, sizeof(policySession));
|
|
XMEMSET(&policyCtx, 0, sizeof(policyCtx));
|
|
#endif
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (XSTRCMP(argv[i], "-?") == 0 ||
|
|
XSTRCMP(argv[i], "-h") == 0 ||
|
|
XSTRCMP(argv[i], "--help") == 0) {
|
|
usage();
|
|
return 0;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--abandon") == 0) {
|
|
abandon = 1;
|
|
}
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
else if (XSTRCMP(argv[i], "--policytest") == 0) {
|
|
policytest = 1;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--policy") == 0) {
|
|
policyMode = IFX_POLICY_CMDCODE;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--policyor") == 0) {
|
|
policyMode = IFX_POLICY_OR;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--sha256") == 0) {
|
|
policyHash = TPM_ALG_SHA256;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--sha384") == 0) {
|
|
policyHash = TPM_ALG_SHA384;
|
|
}
|
|
else if (XSTRCMP(argv[i], "--sha512") == 0) {
|
|
policyHash = TPM_ALG_SHA512;
|
|
}
|
|
#endif /* WOLFTPM_HAVE_FW_POLICY */
|
|
else if (argv[i][0] == '-') {
|
|
printf("Unrecognized option: %s\n", argv[i]);
|
|
usage();
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
else if (manifest_file == NULL) {
|
|
manifest_file = argv[i];
|
|
}
|
|
else if (firmware_file == NULL) {
|
|
firmware_file = argv[i];
|
|
}
|
|
else {
|
|
printf("Unexpected extra argument: %s\n", argv[i]);
|
|
usage();
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
if (policytest) {
|
|
/* Non-destructive validation of caller-supplied policy authorization.
|
|
* Does not touch firmware upgrade state. */
|
|
rc = firmware_policy_selftest_all(&dev);
|
|
wolfTPM2_Cleanup(&dev);
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
rc = wolfTPM2_GetCapabilities(&dev, &caps);
|
|
if (rc != TPM_RC_SUCCESS) {
|
|
goto exit;
|
|
}
|
|
TPM2_IFX_PrintInfo(&caps);
|
|
if (caps.keyGroupId == 0) {
|
|
printf("Error getting key group id from TPM!\n");
|
|
}
|
|
if (caps.opMode == IFX_OPMODE_RECOVERY || (caps.opMode & 0x80)) {
|
|
/* if opmode == 2 or 0x8x then we need to use recovery mode */
|
|
recovery = 1;
|
|
}
|
|
|
|
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");
|
|
}
|
|
goto exit;
|
|
}
|
|
|
|
if (manifest_file == NULL || firmware_file == NULL) {
|
|
if (argc > 1) {
|
|
printf("Manifest file or firmware file arguments missing!\n");
|
|
rc = BAD_FUNC_ARG;
|
|
}
|
|
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);
|
|
}
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
/* When a policy mode is requested, provision the platform authPolicy and
|
|
* build a session that satisfies it, then drive the upgrade under that
|
|
* caller-supplied session instead of the library-managed authorization.
|
|
*
|
|
* Only the normal operational mode actually sends FieldUpgradeStart, which
|
|
* is the one command the session authorizes. In recovery and finalize
|
|
* modes the library skips the start entirely, so provisioning a policy
|
|
* there would install a platform authPolicy that is never exercised - and
|
|
* on a successful run nothing would clear it. Refuse instead of silently
|
|
* changing hierarchy state the user did not ask to change. */
|
|
if (rc == 0 && policyMode != IFX_POLICY_NONE) {
|
|
if (caps.opMode != IFX_OPMODE_NORMAL) {
|
|
printf("Policy authorization requires the normal operational "
|
|
"mode.\n");
|
|
printf(" Current opMode 0x%x does not send FieldUpgradeStart, "
|
|
"so a\n", caps.opMode);
|
|
printf(" caller-supplied session would never be used.\n");
|
|
rc = BAD_FUNC_ARG;
|
|
}
|
|
else {
|
|
rc = firmware_policy_session_setup(&dev, &policyCtx, policyHash,
|
|
(policyMode == IFX_POLICY_OR), TPM_CC_FieldUpgradeStartVendor,
|
|
&policySession);
|
|
}
|
|
}
|
|
#endif
|
|
if (rc == 0) {
|
|
WOLFTPM2_SESSION* startSess = NULL;
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
if (policyMode != IFX_POLICY_NONE) {
|
|
startSess = &policySession;
|
|
}
|
|
#endif
|
|
if (recovery) {
|
|
printf("Firmware Update (recovery mode%s):\n",
|
|
startSess ? ", caller policy" : "");
|
|
rc = wolfTPM2_FirmwareUpgradeRecover_ex(&dev,
|
|
fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz,
|
|
TPM2_IFX_FwData_Cb, &fwinfo, startSess);
|
|
}
|
|
else {
|
|
printf("Firmware Update (normal mode%s):\n",
|
|
startSess ? ", caller policy" : "");
|
|
rc = wolfTPM2_FirmwareUpgrade_ex(&dev,
|
|
fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz,
|
|
TPM2_IFX_FwData_Cb, &fwinfo, startSess);
|
|
}
|
|
}
|
|
if (rc == 0) {
|
|
TPM2_IFX_PrintInfo(&caps);
|
|
}
|
|
|
|
exit:
|
|
|
|
if (rc != 0) {
|
|
printf("Infineon firmware update failed 0x%x: %s\n",
|
|
rc, TPM2_GetRCString(rc));
|
|
}
|
|
|
|
#ifdef WOLFTPM_HAVE_FW_POLICY
|
|
/* On a successful start the TPM consumes the session and the library sets
|
|
* handle.hndl to TPM_RH_NULL (0x40000007), which is non-zero - so this
|
|
* guard does not distinguish consumed from live. It does not need to:
|
|
* wolfTPM2_UnloadHandle is a no-op on TPM_RH_NULL, so the call only ever
|
|
* flushes a session that is still loaded. */
|
|
if (policySession.handle.hndl != 0) {
|
|
wolfTPM2_UnloadHandle(&dev, &policySession.handle);
|
|
}
|
|
/* Clear the platform policy if the upgrade did not complete. Gated on
|
|
* policyCtx.provisioned inside the helper, so an early failure cannot wipe
|
|
* a policy this example never installed.
|
|
*
|
|
* Skip the attempt once the start has succeeded: the TPM consumed the
|
|
* session (handle set to TPM_RH_NULL) and reset into firmware-upgrade
|
|
* mode, where it will not service TPM2_SetPrimaryPolicy - and the
|
|
* mandatory TPM reset clears the policy anyway. */
|
|
if (rc != 0 && policySession.handle.hndl != TPM_RH_NULL) {
|
|
clearRc = firmware_policy_clear(&dev, &policyCtx);
|
|
/* Report a failed rollback, but never overwrite the upgrade error that
|
|
* explains why this run failed - that rc is the process exit status
|
|
* and the only machine-readable diagnostic a script sees. */
|
|
if (clearRc != 0 && rc == 0) {
|
|
rc = clearRc;
|
|
}
|
|
}
|
|
#endif
|
|
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 && (WOLFTPM_SLB9672 || WOLFTPM_SLB9673) &&
|
|
* !WOLFTPM2_NO_WOLFCRYPT */
|
|
|
|
#ifndef NO_MAIN_DRIVER
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rc = -1;
|
|
|
|
#if defined(WOLFTPM_FIRMWARE_UPGRADE) && \
|
|
(defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)) && \
|
|
!defined(WOLFTPM2_NO_WOLFCRYPT)
|
|
rc = TPM2_IFX_Firmware_Update(NULL, argc, argv);
|
|
#else
|
|
printf("Support for firmware upgrade not compiled in!\n"
|
|
"See --enable-firmware or WOLFTPM_FIRMWARE_UPGRADE\n");
|
|
printf("This tool is for the Infineon SLB9672 or SLB9673 TPMs only\n"
|
|
"\t--enable-infineon=slb9672 (WOLFTPM_SLB9672)\n"
|
|
"\t--enable-infineon=slb9673 --enable-i2c (WOLFTPM_SLB9673)\n");
|
|
printf("Firmware upgrade also requires wolfCrypt "
|
|
"(not WOLFTPM2_NO_WOLFCRYPT)\n");
|
|
(void)argc;
|
|
(void)argv;
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
#endif /* !NO_MAIN_DRIVER */
|