diff --git a/CMakeLists.txt b/CMakeLists.txt index a3469ad17..bf78d9ee5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -480,8 +480,13 @@ if (WOLFTPM_EXAMPLES AND BUILD_WOLFTPM_LIB) endif() function(add_tpm_example name src) + # Optional additional sources may be passed after 'src' (ARGN) + set(_example_srcs examples/${src}) + foreach(_extra ${ARGN}) + list(APPEND _example_srcs examples/${_extra}) + endforeach() add_executable(${name} - examples/${src} + ${_example_srcs} ) target_link_libraries(${name} PRIVATE wolftpm tpm_test_lib wolftpm_wolfssl_dep) if(WIN32) @@ -705,7 +710,7 @@ if (WOLFTPM_EXAMPLES AND BUILD_WOLFTPM_LIB) add_tpm_example(secure_rot boot/secure_rot.c) add_tpm_example(csr csr/csr.c) add_tpm_example(get_ek_certs endorsement/get_ek_certs.c) - add_tpm_example(ifx_fw_update firmware/ifx_fw_update.c) + add_tpm_example(ifx_fw_update firmware/ifx_fw_update.c firmware/firmware_policy.c) add_tpm_example(gpio_config gpio/gpio_config.c) add_tpm_example(gpio_read gpio/gpio_read.c) add_tpm_example(gpio_set gpio/gpio_set.c) diff --git a/examples/firmware/README.md b/examples/firmware/README.md index 66d0c60d6..90443526c 100644 --- a/examples/firmware/README.md +++ b/examples/firmware/README.md @@ -199,3 +199,58 @@ Success: Please reset or power cycle TPM ``` **Note**: Firmware files cannot be made public and must be obtained separately from STMicroelectronics. + +## Policy-Based Authorization (Advanced) + +By default wolfTPM manages the platform-hierarchy authorization for the firmware-update *start* command internally: on Infineon it installs and satisfies a `PolicyCommandCode(TPM_CC_FieldUpgradeStartVendor)` policy on the platform primary policy, and on ST33 it uses password authorization (`TPM_RS_PW`) with an empty platform password. This assumes the platform hierarchy has default/empty authorization. + +Deployments that gate firmware upgrade behind their own platform policy (for example a signed-policy check, a PCR state, or a multi-branch `PolicyOR`) can supply an already-satisfied authorization session using `wolfTPM2_FirmwareUpgradeHash_ex()`. When a session is supplied: + +- **Infineon**: the library does **not** overwrite your platform primary policy. You provision the platform `authPolicy` yourself (via `TPM2_SetPrimaryPolicy` with `authHandle = TPM_RH_PLATFORM`, using SHA2-256 or SHA2-512) and pass a session that satisfies it. +- **ST33**: the supplied session replaces the default `TPM_RS_PW` password authorization. + +Both SHA2-256 (non-PQC) and SHA2-512 (PQC) policy digests are supported, because the session hash is chosen with `wolfTPM2_StartSession_ex(..., authHash)` and `wolfTPM2_PolicyOR()` carries per-branch digest sizes. + +Example: satisfy a multi-branch `PolicyOR` (up to 8 branches, SHA2-512 shown) and start the upgrade under it: + +```c +WOLFTPM2_SESSION session; +TPML_DIGEST orList; +uint8_t manifest_hash[TPM_SHA512_DIGEST_SIZE]; +int rc; + +/* zero both structs - orList must not carry uninitialized branch sizes */ +XMEMSET(&session, 0, sizeof(session)); +XMEMSET(&orList, 0, sizeof(orList)); + +/* start a policy session using the desired policy hash (SHA2-512 for PQC) */ +rc = wolfTPM2_StartSession_ex(&dev, &session, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL, TPM_ALG_SHA512); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* Satisfy one branch (PCR, PolicySigned/Authorize, PolicyAuthValue, ...), then + * OR against the full branch list the platform authPolicy encodes. Set count + * and each digests[i].size/buffer for every branch you populate. */ +orList.count = 2; +/* orList.digests[0].size = ...; XMEMCPY(orList.digests[0].buffer, ...); */ +/* orList.digests[1].size = ...; XMEMCPY(orList.digests[1].buffer, ...); */ +rc = wolfTPM2_PolicyOR(&dev, &session, &orList); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* hash the manifest with the matching algorithm, then start the upgrade under + * the caller-satisfied session (NULL would use the library-default auth) */ +rc = wc_Sha512Hash(manifest, manifest_sz, manifest_hash); +if (rc != 0) goto cleanup; +rc = wolfTPM2_FirmwareUpgradeHash_ex(&dev, TPM_ALG_SHA512, + manifest_hash, (uint32_t)sizeof(manifest_hash), + manifest, manifest_sz, fwDataCb, fwCbCtx, &session); + +cleanup: +/* the TPM consumes the session on a successful start; release it otherwise */ +if (session.handle.hndl != 0) + wolfTPM2_UnloadHandle(&dev, &session.handle); +``` + +Passing `NULL` for the final `startSession` argument makes `wolfTPM2_FirmwareUpgradeHash_ex()` behave exactly like `wolfTPM2_FirmwareUpgradeHash()` (library-managed authorization), so existing code is unaffected. + +**Note:** the example `--policy`/`--policyor` modes provision the platform hierarchy `authPolicy` via `TPM2_SetPrimaryPolicy` before the upgrade. On failure the example restores the default (clears the policy) so a later default-auth run is not locked out; on success the required TPM reset clears it. If a run is interrupted before that cleanup, the platform hierarchy may still require the policy until the TPM is reset/power-cycled. diff --git a/examples/firmware/firmware_policy.c b/examples/firmware/firmware_policy.c new file mode 100644 index 000000000..bd00aa40e --- /dev/null +++ b/examples/firmware/firmware_policy.c @@ -0,0 +1,271 @@ +/* firmware_policy.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 +#endif + +#include + +#ifdef WOLFTPM_FIRMWARE_UPGRADE + +#include + +/* Print a digest as hex. Unlike TPM2_PrintBin (a no-op unless DEBUG_WOLFTPM), + * this is always available so the self-test failure report is usable in a + * stock build. */ +static void firmware_print_hex(const byte* buf, word32 len) +{ + word32 j; + for (j = 0; j < len; j++) { + printf("%02x", buf[j]); + } + printf("\n"); +} + +/* Exercise wolfTPM2_PolicyOR at the requested hash and verify the TPM's + * running policy digest matches an offline computation. Non-destructive. + * Returns 0 on match, 1 if the hash is not implemented (intentional skip), + * -1 on digest mismatch, or a TPM rc / BAD_FUNC_ARG on other errors. */ +static int firmware_policy_selftest(WOLFTPM2_DEV* dev, TPMI_ALG_HASH hashAlg, + const char* name) +{ + int rc; + WOLFTPM2_SESSION sess; + TPML_DIGEST orList; + word32 hsz = (word32)TPM2_GetHashDigestSize(hashAlg); + byte branchA[TPM_MAX_DIGEST_SIZE]; + byte branchB[TPM_MAX_DIGEST_SIZE]; + byte concat[2 * TPM_MAX_DIGEST_SIZE]; + byte expected[TPM_MAX_DIGEST_SIZE]; + byte got[TPM_MAX_DIGEST_SIZE]; + word32 aSz, bSz, expSz, gotSz; + + XMEMSET(&sess, 0, sizeof(sess)); + XMEMSET(&orList, 0, sizeof(orList)); + + if (hsz == 0 || hsz > TPM_MAX_DIGEST_SIZE) { + return BAD_FUNC_ARG; + } + + /* Skip cleanly if the TPM firmware does not implement this hash */ + if (!wolfTPM2_IsAlgSupported(dev, hashAlg)) { + printf(" %s: skipped (not implemented by this TPM)\n", name); + return 1; /* intentional skip, not a failure */ + } + + /* Offline: two distinct PolicyCommandCode branch digests */ + aSz = hsz; + rc = wolfTPM2_PolicyCommandCodeMake(hashAlg, branchA, &aSz, TPM_CC_NV_Read); + if (rc == 0) { + bSz = hsz; + rc = wolfTPM2_PolicyCommandCodeMake(hashAlg, branchB, &bSz, + TPM_CC_Unseal); + } + /* Offline PolicyOR digest = H(zeros || TPM_CC_PolicyOR || A || B) */ + if (rc == 0) { + XMEMCPY(concat, branchA, aSz); + XMEMCPY(&concat[aSz], branchB, bSz); + XMEMSET(expected, 0, sizeof(expected)); + expSz = hsz; + rc = wolfTPM2_PolicyHash(hashAlg, expected, &expSz, + TPM_CC_PolicyOR, concat, aSz + bSz); + } + + /* On-TPM: start a policy session using the requested hash algorithm */ + if (rc == 0) { + rc = wolfTPM2_StartSession_ex(dev, &sess, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL, hashAlg); + if (rc != 0) { + printf(" %s: StartSession failed 0x%x: %s\n", + name, rc, TPM2_GetRCString(rc)); + return rc; + } + } + /* Satisfy branch A, then OR against {A,B} with the new wrapper */ + if (rc == 0) { + rc = wolfTPM2_PolicyCommandCode(dev, &sess, TPM_CC_NV_Read); + } + if (rc == 0) { + orList.count = 2; + orList.digests[0].size = (UINT16)aSz; + XMEMCPY(orList.digests[0].buffer, branchA, aSz); + orList.digests[1].size = (UINT16)bSz; + XMEMCPY(orList.digests[1].buffer, branchB, bSz); + rc = wolfTPM2_PolicyOR(dev, &sess, &orList); + } + if (rc == 0) { + gotSz = (word32)sizeof(got); + rc = wolfTPM2_GetPolicyDigest(dev, sess.handle.hndl, got, &gotSz); + } + + if (rc == 0) { + if (gotSz == expSz && XMEMCMP(got, expected, expSz) == 0) { + printf(" %s PolicyOR: PASS (%u byte digest matches)\n", + name, expSz); + } + else { + printf(" %s PolicyOR: FAIL (digest mismatch)\n", name); + printf(" expected: "); + firmware_print_hex(expected, expSz); + printf(" got: "); + firmware_print_hex(got, gotSz); + rc = -1; + } + } + else { + printf(" %s PolicyOR: ERROR 0x%x: %s\n", + name, rc, TPM2_GetRCString(rc)); + } + + wolfTPM2_UnloadHandle(dev, &sess.handle); + return rc; +} + +int firmware_policy_selftest_all(WOLFTPM2_DEV* dev) +{ + int i, rc, hardFail = 0; + struct { TPMI_ALG_HASH alg; const char* name; } hashes[3]; + + hashes[0].alg = TPM_ALG_SHA256; hashes[0].name = "SHA2-256"; + hashes[1].alg = TPM_ALG_SHA384; hashes[1].name = "SHA2-384"; + hashes[2].alg = TPM_ALG_SHA512; hashes[2].name = "SHA2-512"; + + printf("Firmware policy authorization self-test " + "(no firmware changes):\n"); + for (i = 0; i < 3; i++) { + rc = firmware_policy_selftest(dev, hashes[i].alg, hashes[i].name); + /* rc == 1 is an intentional "hash not implemented" skip. Any other + * non-zero (digest mismatch, bad arg, or a TPM rc) is a failure. */ + if (rc != 0 && rc != 1) { + hardFail = 1; + } + } + return hardFail ? -1 : 0; +} + +int firmware_policy_session_setup(WOLFTPM2_DEV* dev, + TPMI_ALG_HASH hashAlg, int useOr, TPM_CC fuStartCC, + WOLFTPM2_SESSION* session) +{ + int rc; + int provisioned = 0; + TPML_DIGEST orList; + word32 hsz = (word32)TPM2_GetHashDigestSize(hashAlg); + byte branchA[TPM_MAX_DIGEST_SIZE]; + byte branchB[TPM_MAX_DIGEST_SIZE]; + byte concat[2 * TPM_MAX_DIGEST_SIZE]; + byte platformPolicy[TPM_MAX_DIGEST_SIZE]; + word32 aSz, bSz = 0, polSz = 0; + + if (hsz == 0 || hsz > TPM_MAX_DIGEST_SIZE) { + return BAD_FUNC_ARG; + } + XMEMSET(session, 0, sizeof(*session)); + XMEMSET(&orList, 0, sizeof(orList)); + + /* Fail early (before provisioning) if the TPM can't use this policy hash */ + if (!wolfTPM2_IsAlgSupported(dev, hashAlg)) { + printf("Policy hash %s not implemented by this TPM\n", + TPM2_GetAlgName(hashAlg)); + return BAD_FUNC_ARG; + } + + printf("Provisioning platform policy (%s, %s)\n", + useOr ? "PolicyOR" : "PolicyCommandCode", + TPM2_GetAlgName(hashAlg)); + + /* Branch A: PolicyCommandCode(FieldUpgradeStart) - required to start FU */ + aSz = hsz; + rc = wolfTPM2_PolicyCommandCodeMake(hashAlg, branchA, &aSz, fuStartCC); + + /* Compute the platform authPolicy digest */ + if (rc == 0) { + if (useOr) { + /* Branch B: a second, distinct policy branch */ + bSz = hsz; + rc = wolfTPM2_PolicyCommandCodeMake(hashAlg, branchB, &bSz, + TPM_CC_NV_Read); + if (rc == 0) { + XMEMCPY(concat, branchA, aSz); + XMEMCPY(&concat[aSz], branchB, bSz); + XMEMSET(platformPolicy, 0, sizeof(platformPolicy)); + polSz = hsz; + rc = wolfTPM2_PolicyHash(hashAlg, platformPolicy, &polSz, + TPM_CC_PolicyOR, concat, aSz + bSz); + } + } + else { + XMEMCPY(platformPolicy, branchA, aSz); + polSz = aSz; + } + } + + /* Provision the platform primary policy (empty platformAuth) */ + if (rc == 0) { + rc = wolfTPM2_SetPrimaryPolicy(dev, TPM_RH_PLATFORM, hashAlg, + platformPolicy, polSz); + if (rc != 0) { + printf(" SetPrimaryPolicy failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } + else { + provisioned = 1; + } + } + + /* Start a policy session and satisfy the platform policy */ + if (rc == 0) { + rc = wolfTPM2_StartSession_ex(dev, session, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL, hashAlg); + if (rc != 0) { + printf(" StartSession failed 0x%x: %s\n", + rc, TPM2_GetRCString(rc)); + } + } + if (rc == 0) { + rc = wolfTPM2_PolicyCommandCode(dev, session, fuStartCC); + } + if (rc == 0 && useOr) { + orList.count = 2; + orList.digests[0].size = (UINT16)aSz; + XMEMCPY(orList.digests[0].buffer, branchA, aSz); + orList.digests[1].size = (UINT16)bSz; + XMEMCPY(orList.digests[1].buffer, branchB, bSz); + rc = wolfTPM2_PolicyOR(dev, session, &orList); + } + + if (rc != 0) { + if (session->handle.hndl != 0) { + wolfTPM2_UnloadHandle(dev, &session->handle); + } + /* Restore default platform auth so a later run is not locked out (the + * platform policy is otherwise cleared only on TPM reset). */ + if (provisioned && + wolfTPM2_SetPrimaryPolicy(dev, TPM_RH_PLATFORM, TPM_ALG_NULL, + NULL, 0) == TPM_RC_SUCCESS) { + printf(" Cleared platform policy after setup failure\n"); + } + } + return rc; +} + +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ diff --git a/examples/firmware/firmware_policy.h b/examples/firmware/firmware_policy.h new file mode 100644 index 000000000..b5dd1ea81 --- /dev/null +++ b/examples/firmware/firmware_policy.h @@ -0,0 +1,60 @@ +/* firmware_policy.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 + */ + +/* Shared caller-supplied policy authorization helpers for the firmware update + * examples (ifx_fw_update and st33_fw_update). The vendor difference is carried + * by the fuStartCC parameter, so there is no per-vendor logic here. */ + +#ifndef WOLFTPM_EXAMPLE_FIRMWARE_POLICY_H +#define WOLFTPM_EXAMPLE_FIRMWARE_POLICY_H + +#include + +#ifdef WOLFTPM_FIRMWARE_UPGRADE + +#ifdef __cplusplus +extern "C" { +#endif + +/* Non-destructive self-test: exercises wolfTPM2_PolicyOR at SHA-256/384/512 and + * checks the TPM's running policy digest against an offline computation. A hash + * the TPM does not implement is reported and skipped. Returns 0 on overall + * success (all supported hashes matched), -1 if any supported hash failed. */ +WOLFTPM_LOCAL int firmware_policy_selftest_all(WOLFTPM2_DEV* dev); + +/* Provision the platform authPolicy and return a session that satisfies it, so + * the firmware-start command can be authorized by a caller-controlled policy + * instead of the vendor default. When useOr is set the platform policy is a + * PolicyOR of two branches; otherwise a single PolicyCommandCode branch. + * fuStartCC is the vendor FieldUpgrade start command code. On success *session + * is started and satisfied (the caller passes it to wolfTPM2_FirmwareUpgrade_ex + * and must UnloadHandle it). On failure any provisioned platform policy is + * cleared so a later default-auth run is not locked out. */ +WOLFTPM_LOCAL int firmware_policy_session_setup(WOLFTPM2_DEV* dev, + TPMI_ALG_HASH hashAlg, int useOr, TPM_CC fuStartCC, + WOLFTPM2_SESSION* session); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFTPM_FIRMWARE_UPGRADE */ +#endif /* WOLFTPM_EXAMPLE_FIRMWARE_POLICY_H */ diff --git a/examples/firmware/ifx_fw_update.c b/examples/firmware/ifx_fw_update.c index 9934e229b..419dafc80 100644 --- a/examples/firmware/ifx_fw_update.c +++ b/examples/firmware/ifx_fw_update.c @@ -32,6 +32,7 @@ (defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)) #include +#include #include #include @@ -44,7 +45,14 @@ 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"); + printf("\t./ifx_fw_update --policytest (safe policy auth self-test)\n"); + printf("\t./ifx_fw_update [policy opts] \n"); + printf("\t./ifx_fw_update " + "(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 { @@ -115,24 +123,59 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) const char* firmware_file = NULL; fw_info_t fwinfo; int abandon = 0, recovery = 0; + int policytest = 0; + int policyMode = 0; /* 0=default auth, 1=--policy, 2=--policyor */ + TPMI_ALG_HASH policyHash = TPM_ALG_SHA256; + WOLFTPM2_SESSION policySession; + int sessionStarted = 0; /* set once session handed to FieldUpgradeStart */ + int i; XMEMSET(&fwinfo, 0, sizeof(fwinfo)); + XMEMSET(&policySession, 0, sizeof(policySession)); - if (argc >= 2) { - if (XSTRCMP(argv[1], "-?") == 0 || - XSTRCMP(argv[1], "-h") == 0 || - XSTRCMP(argv[1], "--help") == 0) { + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "-?") == 0 || + XSTRCMP(argv[i], "-h") == 0 || + XSTRCMP(argv[i], "--help") == 0) { usage(); return 0; } - if (XSTRCMP(argv[1], "--abandon") == 0) { + else if (XSTRCMP(argv[i], "--abandon") == 0) { abandon = 1; } + else if (XSTRCMP(argv[i], "--policytest") == 0) { + policytest = 1; + } + else if (XSTRCMP(argv[i], "--policy") == 0) { + policyMode = 1; + } + else if (XSTRCMP(argv[i], "--policyor") == 0) { + policyMode = 2; + } + 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; + } + 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 { - manifest_file = argv[1]; - if (argc >= 3) { - firmware_file = argv[2]; - } + printf("Unexpected extra argument: %s\n", argv[i]); + usage(); + return BAD_FUNC_ARG; } } @@ -148,6 +191,13 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) goto exit; } + if (policytest) { + /* Non-destructive validation of caller-supplied policy authorization. + * Does not touch firmware upgrade state. */ + rc = firmware_policy_selftest_all(&dev); + goto exit; + } + rc = wolfTPM2_GetCapabilities(&dev, &caps); if (rc != TPM_RC_SUCCESS) { goto exit; @@ -187,18 +237,35 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) rc = loadFile(firmware_file, &fwinfo.firmware_buf, &fwinfo.firmware_bufSz); } + /* 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. */ + if (rc == 0 && policyMode != 0) { + rc = firmware_policy_session_setup(&dev, policyHash, + (policyMode == 2), TPM_CC_FieldUpgradeStartVendor, &policySession); + } if (rc == 0) { + /* The upgrade hands the session to FieldUpgradeStart, which the TPM + * consumes as it enters upgrade mode. opMode 0x03 (finalize-only) does + * not reach start, so the session there is not consumed. */ + if (policyMode) { + sessionStarted = (caps.opMode != 0x03); + } if (recovery) { - printf("Firmware Update (recovery mode):\n"); - rc = wolfTPM2_FirmwareUpgradeRecover(&dev, + printf("Firmware Update (recovery mode%s):\n", + policyMode ? ", caller policy" : ""); + rc = wolfTPM2_FirmwareUpgradeRecover_ex(&dev, fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, - TPM2_IFX_FwData_Cb, &fwinfo); + TPM2_IFX_FwData_Cb, &fwinfo, + policyMode ? &policySession : NULL); } else { - printf("Firmware Update (normal mode):\n"); - rc = wolfTPM2_FirmwareUpgrade(&dev, + printf("Firmware Update (normal mode%s):\n", + policyMode ? ", caller policy" : ""); + rc = wolfTPM2_FirmwareUpgrade_ex(&dev, fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, - TPM2_IFX_FwData_Cb, &fwinfo); + TPM2_IFX_FwData_Cb, &fwinfo, + policyMode ? &policySession : NULL); } } if (rc == 0) { @@ -212,6 +279,12 @@ int TPM2_IFX_Firmware_Update(void* userCtx, int argc, char *argv[]) rc, TPM2_GetRCString(rc)); } + /* Release the session only if it was not handed to a FieldUpgradeStart + * (which the TPM consumes). This avoids both a stale FlushContext after a + * consumed start and a leaked session when start was never reached. */ + if (!sessionStarted && policySession.handle.hndl != 0) { + wolfTPM2_UnloadHandle(&dev, &policySession.handle); + } XFREE(fwinfo.firmware_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(fwinfo.manifest_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); wolfTPM2_Cleanup(&dev); diff --git a/examples/firmware/include.am b/examples/firmware/include.am index 4c355b856..c54448998 100644 --- a/examples/firmware/include.am +++ b/examples/firmware/include.am @@ -7,13 +7,19 @@ EXTRA_DIST += examples/firmware/Makefile # Host side tool for extracting the firmware manifest and data 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 + if BUILD_EXAMPLES if BUILD_FIRMWARE if BUILD_INFINEON noinst_PROGRAMS += examples/firmware/ifx_fw_update noinst_HEADERS += examples/firmware/ifx_fw_update.h +noinst_HEADERS += examples/firmware/firmware_policy.h examples_firmware_ifx_fw_update_SOURCES = examples/firmware/ifx_fw_update.c \ + examples/firmware/firmware_policy.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 @@ -22,6 +28,7 @@ endif 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/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 diff --git a/examples/firmware/st33_fw_update.c b/examples/firmware/st33_fw_update.c index 2120df3db..c770fae9a 100644 --- a/examples/firmware/st33_fw_update.c +++ b/examples/firmware/st33_fw_update.c @@ -31,6 +31,7 @@ #if defined(WOLFTPM_FIRMWARE_UPGRADE) && \ (defined(WOLFTPM_ST33) || defined(WOLFTPM_AUTODETECT)) +#include #include #include @@ -47,7 +48,13 @@ static void usage(void) printf("ST33 Firmware Update Usage:\n"); printf("\t./st33_fw_update (get info)\n"); printf("\t./st33_fw_update --abandon (cancel)\n"); - printf("\t./st33_fw_update \n"); + printf("\t./st33_fw_update --policytest (safe policy auth self-test)\n"); + printf("\t./st33_fw_update [policy opts] \n"); + printf("\t./st33_fw_update (default password 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"); printf("\nFirmware format is auto-detected from the TPM firmware version.\n"); printf("Just provide the correct .fi file for your TPM and it will be handled automatically.\n"); } @@ -184,23 +191,58 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) const char* fi_file = NULL; fw_info_t fwinfo; int abandon = 0; + int policytest = 0; + int policyMode = 0; /* 0=default auth, 1=--policy, 2=--policyor */ + TPMI_ALG_HASH policyHash = TPM_ALG_SHA256; + WOLFTPM2_SESSION policySession; + int sessionStarted = 0; /* set once session handed to FieldUpgradeStart */ size_t blob0_size; + int i; XMEMSET(&fwinfo, 0, sizeof(fwinfo)); XMEMSET(&caps, 0, sizeof(caps)); + XMEMSET(&policySession, 0, sizeof(policySession)); - if (argc >= 2) { - if (XSTRCMP(argv[1], "-?") == 0 || - XSTRCMP(argv[1], "-h") == 0 || - XSTRCMP(argv[1], "--help") == 0) { + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "-?") == 0 || + XSTRCMP(argv[i], "-h") == 0 || + XSTRCMP(argv[i], "--help") == 0) { usage(); return 0; } - if (XSTRCMP(argv[1], "--abandon") == 0) { + else if (XSTRCMP(argv[i], "--abandon") == 0) { abandon = 1; } + else if (XSTRCMP(argv[i], "--policytest") == 0) { + policytest = 1; + } + else if (XSTRCMP(argv[i], "--policy") == 0) { + policyMode = 1; + } + else if (XSTRCMP(argv[i], "--policyor") == 0) { + policyMode = 2; + } + 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; + } + else if (argv[i][0] == '-') { + printf("Unrecognized option: %s\n", argv[i]); + usage(); + return BAD_FUNC_ARG; + } + else if (fi_file == NULL) { + fi_file = argv[i]; + } else { - fi_file = argv[1]; + printf("Unexpected extra argument: %s\n", argv[i]); + usage(); + return BAD_FUNC_ARG; } } @@ -245,6 +287,16 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) goto exit; } + if (policytest) { + /* Non-destructive validation of caller-supplied policy authorization. + * Runs SHA2-256/384/512 PolicyOR digest checks (a hash the TPM does + * not support is reported and skipped). Does not touch firmware + * upgrade state. */ + rc = firmware_policy_selftest_all(&dev); + wolfTPM2_Cleanup(&dev); + return rc; + } + rc = wolfTPM2_GetCapabilities(&dev, &caps); if (rc != TPM_RC_SUCCESS) { printf("wolfTPM2_GetCapabilities failed 0x%x: %s\n", @@ -351,10 +403,26 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) rc = TPM2_ST33_SendFirmwareData(&fwinfo); } else { - /* Normal mode - use unified API which auto-detects format from manifest size */ - rc = wolfTPM2_FirmwareUpgrade(&dev, - fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, - TPM2_ST33_FwData_Cb, &fwinfo); + /* 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 default password auth. */ + if (policyMode != 0) { + rc = firmware_policy_session_setup(&dev, policyHash, + (policyMode == 2), TPM_CC_FieldUpgradeStartVendor_ST33, + &policySession); + } + /* Normal mode - unified API auto-detects format from manifest size */ + if (rc == 0) { + if (policyMode) { + printf("Using caller-supplied policy session\n"); + /* session is handed to FieldUpgradeStart, which consumes it */ + sessionStarted = 1; + } + rc = wolfTPM2_FirmwareUpgrade_ex(&dev, + fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz, + TPM2_ST33_FwData_Cb, &fwinfo, + policyMode ? &policySession : NULL); + } } if (rc == 0) { printf("\nFirmware update completed successfully.\n"); @@ -377,6 +445,12 @@ int TPM2_ST33_Firmware_Update(void* userCtx, int argc, char *argv[]) rc, TPM2_GetRCString(rc)); } + /* Release the session only if it was not handed to a FieldUpgradeStart + * (which the TPM consumes). This avoids both a stale FlushContext after a + * consumed start and a leaked session when start was never reached. */ + if (!sessionStarted && policySession.handle.hndl != 0) { + wolfTPM2_UnloadHandle(&dev, &policySession.handle); + } /* Only free the main fi_buf - manifest_buf and firmware_buf point into it */ XFREE(fwinfo.fi_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); wolfTPM2_Cleanup(&dev); diff --git a/examples/nvram/extend.c b/examples/nvram/extend.c index 1601bdd0e..5d5558eac 100644 --- a/examples/nvram/extend.c +++ b/examples/nvram/extend.c @@ -50,14 +50,6 @@ static void usage(void) printf("* -aes/xor: Use Parameter Encryption\n");; } -static int BuildPolicyCommandCode(TPMI_ALG_HASH hashAlg, - byte* digest, word32* digestSz, TPM_CC cc) -{ - word32 val = cpu_to_be32(cc); - return wolfTPM2_PolicyHash(hashAlg, digest, digestSz, - TPM_CC_PolicyCommandCode, (byte*)&val, sizeof(val)); -} - static int PolicyOrApply(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* policySession, byte** hashList, word32 hashListSz, word32 digestSz) { @@ -161,7 +153,7 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy A: TPM2_PolicyCommandCode -> TPM_CC_NV_Read */ /* 47ce3032d8bad1f3089cb0c09088de43501491d460402b90cd1b7fc0b68ca92f */ policy[0] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[0], &nvSize, TPM_CC_NV_Read); + wolfTPM2_PolicyCommandCodeMake(hashAlg, policy[0], &nvSize, TPM_CC_NV_Read); printf("PolicyA: %d\n", nvSize); TPM2_PrintBin(policy[0], nvSize); policyDigestSz += nvSize; @@ -169,7 +161,7 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy B: TPM2_PolicyCommandCode -> TPM_CC_NV_Extend */ /* b6a2e7142ee56fd978047488483daa5b42b8dc4cc7ddcceddfb91793cf1ff1b7 */ policy[1] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[1], &nvSize, TPM_CC_NV_Extend); + wolfTPM2_PolicyCommandCodeMake(hashAlg, policy[1], &nvSize, TPM_CC_NV_Extend); printf("PolicyB: %d\n", nvSize); TPM2_PrintBin(policy[1], nvSize); policyDigestSz += nvSize; @@ -177,7 +169,7 @@ int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) /* Policy C: TPM2_PolicyCommandCode -> TPM_CC_PolicyNV */ /* 203e4bd5d0448c9615cc13fa18e8d39222441cc40204d99a77262068dbd55a43 */ policy[2] = &policyDigest[policyDigestSz]; - BuildPolicyCommandCode(hashAlg, policy[2], &nvSize, TPM_CC_PolicyNV); + wolfTPM2_PolicyCommandCodeMake(hashAlg, policy[2], &nvSize, TPM_CC_PolicyNV); printf("PolicyC: %d\n", nvSize); TPM2_PrintBin(policy[2], nvSize); policyDigestSz += nvSize; diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 041931b09..0c997f7fd 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -1010,6 +1010,33 @@ int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* cap) return wolfTPM2_GetCapabilities_NoDev(cap); } +/* Return 1 if the TPM implements the given algorithm, 0 otherwise. + * Queries TPM_CAP_ALGS: the TPM returns algorithms with ID >= property, so a + * match at index 0 for a single-property query means it is implemented. */ +int wolfTPM2_IsAlgSupported(WOLFTPM2_DEV* dev, TPM_ALG_ID alg) +{ + GetCapability_In in; + GetCapability_Out out; + TPML_ALG_PROPERTY* algs; + + if (dev == NULL) { + return 0; + } + XMEMSET(&in, 0, sizeof(in)); + XMEMSET(&out, 0, sizeof(out)); + in.capability = TPM_CAP_ALGS; + in.property = alg; + in.propertyCount = 1; + if (TPM2_GetCapability(&in, &out) != TPM_RC_SUCCESS) { + return 0; /* conservative: treat query failure as unsupported */ + } + algs = &out.capabilityData.data.algorithms; + if (algs->count >= 1 && algs->algProperties[0].alg == alg) { + return 1; + } + return 0; +} + int wolfTPM2_GetHandles(TPM_HANDLE handle, TPML_HANDLE* handles) { int rc; @@ -10663,6 +10690,64 @@ int wolfTPM2_PolicyCommandCode(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, return TPM2_PolicyCommandCode(&policyCC); } +/* Satisfy a policy session with a compound OR of pre-computed policy digests. + * The digest list is hash-agnostic (each branch carries its own size), so it + * works for SHA2-256 as well as SHA2-512 policy branches. */ +int wolfTPM2_PolicyOR(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, + const TPML_DIGEST* pHashList) +{ + PolicyOR_In policyOR; + word32 i; + + if (dev == NULL || tpmSession == NULL || pHashList == NULL) { + return BAD_FUNC_ARG; + } + if (pHashList->count == 0 || + pHashList->count > (word32)(sizeof(pHashList->digests) / + sizeof(pHashList->digests[0]))) { + return BAD_FUNC_ARG; + } + /* Validate each branch digest size against its buffer so TPM2_PolicyOR + * cannot marshal past the fixed digest buffer (out-of-bounds read). */ + for (i = 0; i < pHashList->count; i++) { + if (pHashList->digests[i].size > + (UINT16)sizeof(pHashList->digests[i].buffer)) { + return BAD_FUNC_ARG; + } + } + + XMEMSET(&policyOR, 0, sizeof(policyOR)); + policyOR.policySession = tpmSession->handle.hndl; + XMEMCPY(&policyOR.pHashList, pHashList, sizeof(policyOR.pHashList)); + return TPM2_PolicyOR(&policyOR); +} + +/* Set (or clear) the authPolicy for a hierarchy (owner/endorsement/platform/ + * lockout). Pass authPolicy=NULL/authPolicySz=0 with hashAlg=TPM_ALG_NULL to + * clear an existing policy. */ +int wolfTPM2_SetPrimaryPolicy(WOLFTPM2_DEV* dev, + TPMI_RH_HIERARCHY_AUTH authHandle, TPM_ALG_ID hashAlg, + const byte* authPolicy, word32 authPolicySz) +{ + SetPrimaryPolicy_In in; + + if (dev == NULL) { + return BAD_FUNC_ARG; + } + if (authPolicySz > (word32)sizeof(in.authPolicy.buffer)) { + return BAD_FUNC_ARG; + } + + XMEMSET(&in, 0, sizeof(in)); + in.authHandle = authHandle; + in.hashAlg = hashAlg; + if (authPolicy != NULL && authPolicySz > 0) { + in.authPolicy.size = (UINT16)authPolicySz; + XMEMCPY(in.authPolicy.buffer, authPolicy, authPolicySz); + } + return TPM2_SetPrimaryPolicy(&in); +} + #ifndef WOLFTPM2_NO_WOLFCRYPT /* Authorize a policy based on external key for a verified policy digiest signature */ int wolfTPM2_PolicyAuthorize(WOLFTPM2_DEV* dev, TPM_HANDLE sessionHandle, @@ -10829,6 +10914,33 @@ int wolfTPM2_PolicyHash(TPM_ALG_ID hashAlg, return rc; } +/* Assemble a PolicyCommandCode digest for a fresh policy session */ +/* policyDigest = hash(zeroDigest || TPM_CC_PolicyCommandCode || cc) */ +int wolfTPM2_PolicyCommandCodeMake(TPM_ALG_ID hashAlg, + byte* digest, word32* digestSz, TPM_CC cc) +{ + int hashSz; + byte val[4]; /* command code big-endian, matching the TPM wire format */ + + if (digest == NULL || digestSz == NULL) { + return BAD_FUNC_ARG; + } + hashSz = TPM2_GetHashDigestSize(hashAlg); + if (hashSz <= 0) { + return BAD_FUNC_ARG; + } + /* fresh policy session starts from a zero digest of the hash size */ + XMEMSET(digest, 0, hashSz); + *digestSz = (word32)hashSz; + + val[0] = (byte)((cc >> 24) & 0xFF); + val[1] = (byte)((cc >> 16) & 0xFF); + val[2] = (byte)((cc >> 8) & 0xFF); + val[3] = (byte)(cc & 0xFF); + return wolfTPM2_PolicyHash(hashAlg, digest, digestSz, + TPM_CC_PolicyCommandCode, val, sizeof(val)); +} + /* Assemble a PCR policy */ /* policyDigestnew = hash(policyDigestOld || TPM_CC_PolicyPCR || PCRS || * pcrDigest) */ @@ -11055,11 +11167,12 @@ int wolfTPM2_SetIdentityAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle, static int tpm2_ifx_firmware_enable_policy(WOLFTPM2_DEV* dev) { int rc; - SetPrimaryPolicy_In policy; + byte policyDigest[TPM_MAX_DIGEST_SIZE]; + word32 policySz = (word32)sizeof(policyDigest); WOLFTPM2_SESSION tpmSession; XMEMSET(&tpmSession, 0, sizeof(tpmSession)); - XMEMSET(&policy, 0, sizeof(policy)); + XMEMSET(policyDigest, 0, sizeof(policyDigest)); rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL, TPM_SE_POLICY, TPM_ALG_NULL); @@ -11067,17 +11180,15 @@ static int tpm2_ifx_firmware_enable_policy(WOLFTPM2_DEV* dev) rc = wolfTPM2_PolicyCommandCode(dev, &tpmSession, TPM_CC_FieldUpgradeStartVendor); if (rc == TPM_RC_SUCCESS) { - word32 policySz = (word32)sizeof(policy.authPolicy.buffer); + policySz = (word32)sizeof(policyDigest); rc = wolfTPM2_GetPolicyDigest(dev, tpmSession.handle.hndl, - policy.authPolicy.buffer, &policySz); - policy.authPolicy.size = policySz; + policyDigest, &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); + rc = wolfTPM2_SetPrimaryPolicy(dev, TPM_RH_PLATFORM, TPM_ALG_SHA256, + policyDigest, policySz); } #ifdef DEBUG_WOLFTPM @@ -11090,52 +11201,70 @@ static int tpm2_ifx_firmware_enable_policy(WOLFTPM2_DEV* dev) } static int tpm2_ifx_firmware_start(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, - uint8_t* manifest_hash, uint32_t manifest_hash_sz) + uint8_t* manifest_hash, uint32_t manifest_hash_sz, + WOLFTPM2_SESSION* startSession) { int rc; WOLFTPM2_SESSION tpmSession; + TPM_HANDLE sessionHandle = TPM_RH_NULL; + int ownSession = 0; XMEMSET(&tpmSession, 0, sizeof(tpmSession)); - rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL, - TPM_SE_POLICY, TPM_ALG_NULL); - if (rc == TPM_RC_SUCCESS) { - rc = wolfTPM2_PolicyCommandCode(dev, &tpmSession, - TPM_CC_FieldUpgradeStartVendor); - 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 (startSession != NULL) { + /* Caller has already satisfied the platform policy on this session */ + sessionHandle = startSession->handle.hndl; + rc = TPM_RC_SUCCESS; + } + else { + /* Default: internal policy session asserting the firmware start + * command code, matching the policy installed on the platform + * hierarchy by tpm2_ifx_firmware_enable_policy */ + rc = wolfTPM2_StartSession(dev, &tpmSession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); 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 */ - #ifdef WOLFTPM_LINUX_DEV_AUTODETECT - if (dev->ctx.fd < 0) /* Only needed for SPI path */ - #endif - rc = TPM2_ChipStartup(&dev->ctx, 10); - #endif - } - else { - wolfTPM2_UnloadHandle(dev, &tpmSession.handle); + ownSession = 1; + sessionHandle = tpmSession.handle.hndl; + rc = wolfTPM2_PolicyCommandCode(dev, &tpmSession, + TPM_CC_FieldUpgradeStartVendor); } } + + 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(sessionHandle, + 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 */ + #ifdef WOLFTPM_LINUX_DEV_AUTODETECT + if (dev->ctx.fd < 0) /* Only needed for SPI path */ + #endif + rc = TPM2_ChipStartup(&dev->ctx, 10); + #endif + } + else if (ownSession) { + /* only release a session we started ourselves */ + wolfTPM2_UnloadHandle(dev, &tpmSession.handle); + } #ifdef DEBUG_WOLFTPM if (rc != TPM_RC_SUCCESS) { printf("Firmware upgrade start failed 0x%x: %s\n", @@ -11291,7 +11420,7 @@ static int tpm2_ifx_firmware_final(WOLFTPM2_DEV* dev) static int tpm2_st33_firmware_upgrade_hash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, uint8_t* manifest_hash, uint32_t manifest_hash_sz, uint8_t* manifest, uint32_t manifest_sz, - wolfTPM2FwDataCb cb, void* cb_ctx); + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession); static int tpm2_st33_firmware_cancel(WOLFTPM2_DEV* dev); #endif @@ -11299,6 +11428,17 @@ int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, uint8_t* manifest_hash, uint32_t manifest_hash_sz, uint8_t* manifest, uint32_t manifest_sz, wolfTPM2FwDataCb cb, void* cb_ctx) +{ + /* Default behavior: library-managed platform authorization */ + return wolfTPM2_FirmwareUpgradeHash_ex(dev, hashAlg, + manifest_hash, manifest_hash_sz, manifest, manifest_sz, + cb, cb_ctx, NULL); +} + +int wolfTPM2_FirmwareUpgradeHash_ex(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, + uint8_t* manifest_hash, uint32_t manifest_hash_sz, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession) { int rc; WOLFTPM2_CAPS caps; @@ -11316,7 +11456,7 @@ int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, return tpm2_st33_firmware_upgrade_hash(dev, hashAlg, manifest_hash, manifest_hash_sz, manifest, manifest_sz, - cb, cb_ctx); + cb, cb_ctx, startSession); } #endif @@ -11332,10 +11472,18 @@ int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, return tpm2_ifx_firmware_final(dev); } if (caps.opMode == 0x00) { - rc = tpm2_ifx_firmware_enable_policy(dev); + /* Ensure rc is assigned in this scope regardless of the branch + * below (the caller-session path does not call enable_policy). */ + rc = TPM_RC_SUCCESS; + /* When the caller supplies a session it must already satisfy the + * platform authPolicy, so do not overwrite the platform primary + * policy - only manage it for the library-default path */ + if (startSession == NULL) { + rc = tpm2_ifx_firmware_enable_policy(dev); + } if (rc == TPM_RC_SUCCESS) { rc = tpm2_ifx_firmware_start(dev, hashAlg, - manifest_hash, manifest_hash_sz); + manifest_hash, manifest_hash_sz, startSession); } } if (rc == TPM_RC_SUCCESS) { @@ -11365,9 +11513,9 @@ int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, } #ifndef WOLFTPM2_NO_WOLFCRYPT -int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, +int wolfTPM2_FirmwareUpgrade_ex(WOLFTPM2_DEV* dev, uint8_t* manifest, uint32_t manifest_sz, - wolfTPM2FwDataCb cb, void* cb_ctx) + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession) { #ifdef WOLFSSL_SHA384 int rc; @@ -11376,31 +11524,49 @@ int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, /* hash the manifest */ rc = wc_Sha384Hash(manifest, manifest_sz, manifest_hash); if (rc == 0) { - rc = wolfTPM2_FirmwareUpgradeHash(dev, TPM_ALG_SHA384, + rc = wolfTPM2_FirmwareUpgradeHash_ex(dev, TPM_ALG_SHA384, manifest_hash, (uint32_t)sizeof(manifest_hash), - manifest, manifest_sz, cb, cb_ctx); + manifest, manifest_sz, cb, cb_ctx, startSession); } return rc; #else (void)dev; (void)manifest; (void)manifest_sz; - (void)cb; (void)cb_ctx; + (void)cb; (void)cb_ctx; (void)startSession; return NOT_COMPILED_IN; #endif } -#endif -int wolfTPM2_FirmwareUpgradeRecover(WOLFTPM2_DEV* dev, +int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, uint8_t* manifest, uint32_t manifest_sz, wolfTPM2FwDataCb cb, void* cb_ctx) +{ + /* Default behavior: library-managed platform authorization */ + return wolfTPM2_FirmwareUpgrade_ex(dev, manifest, manifest_sz, + cb, cb_ctx, NULL); +} +#endif + +int wolfTPM2_FirmwareUpgradeRecover_ex(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession) { uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE]; /* recovery mode manifest hash is all 0x3C */ XMEMSET(manifest_hash, 0x3C, sizeof(manifest_hash)); - return wolfTPM2_FirmwareUpgradeHash(dev, TPM_ALG_SHA384, + return wolfTPM2_FirmwareUpgradeHash_ex(dev, TPM_ALG_SHA384, manifest_hash, (uint32_t)sizeof(manifest_hash), - manifest, manifest_sz, cb, cb_ctx); + manifest, manifest_sz, cb, cb_ctx, startSession); +} + +int wolfTPM2_FirmwareUpgradeRecover(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx) +{ + /* Default behavior: library-managed platform authorization */ + return wolfTPM2_FirmwareUpgradeRecover_ex(dev, manifest, manifest_sz, + cb, cb_ctx, NULL); } /* terminate a firmware update */ @@ -11474,17 +11640,23 @@ int wolfTPM2_FirmwareUpgradeCancel(WOLFTPM2_DEV* dev) * 300ms delay: ST reference implementation uses this delay to allow * TPM to switch modes after FieldUpgradeStart command */ static int tpm2_st33_firmware_start_common(WOLFTPM2_DEV* dev, - uint8_t* manifest, uint32_t manifest_sz, int is_lms) + uint8_t* manifest, uint32_t manifest_sz, int is_lms, + WOLFTPM2_SESSION* startSession) { int rc; + TPM_HANDLE sessionHandle; (void)dev; - /* ST33 uses password auth (TPM_RS_PW) for FieldUpgradeStart. - * This matches the ST reference implementation behavior. + /* By default ST33 uses password auth (TPM_RS_PW) for FieldUpgradeStart, + * matching the ST reference implementation behavior. When the caller + * supplies a session (for example a policy session that satisfies a + * custom platform authPolicy), use it instead. * For LMS format, the manifest (blob0) already contains the embedded * LMS signature. Send the full manifest directly. */ - rc = TPM2_ST33_FieldUpgradeStart(TPM_RS_PW, manifest, manifest_sz); + sessionHandle = (startSession != NULL) ? + startSession->handle.hndl : (TPM_HANDLE)TPM_RS_PW; + rc = TPM2_ST33_FieldUpgradeStart(sessionHandle, manifest, manifest_sz); if (rc == TPM_RC_SUCCESS) { /* 300ms delay: ST reference implementation uses this delay to allow @@ -11643,7 +11815,7 @@ static int tpm2_st33_firmware_data(WOLFTPM2_DEV* dev, static int tpm2_st33_firmware_upgrade_hash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg, uint8_t* manifest_hash, uint32_t manifest_hash_sz, uint8_t* manifest, uint32_t manifest_sz, - wolfTPM2FwDataCb cb, void* cb_ctx) + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession) { int rc; WOLFTPM2_CAPS caps; @@ -11717,7 +11889,8 @@ static int tpm2_st33_firmware_upgrade_hash(WOLFTPM2_DEV* dev, TPM_ALG_ID hashAlg } /* Send manifest - the common function handles both LMS and non-LMS */ - rc = tpm2_st33_firmware_start_common(dev, manifest, manifest_sz, is_lms); + rc = tpm2_st33_firmware_start_common(dev, manifest, manifest_sz, is_lms, + startSession); if (rc == TPM_RC_SUCCESS) { rc = tpm2_st33_firmware_data(dev, cb, cb_ctx); diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 8dd121176..9c3612af3 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -281,6 +281,7 @@ static void test_wolfTPM2_ReadPublicKey(void) static void test_wolfTPM2_ST33_FirmwareUpgrade(void) { int rc; + int rcEx; WOLFTPM2_DEV dev; WOLFTPM2_CAPS caps; #if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFSSL_SHA384) @@ -322,10 +323,28 @@ static void test_wolfTPM2_ST33_FirmwareUpgrade(void) rc = wolfTPM2_FirmwareUpgradeRecover(NULL, NULL, 0, NULL, NULL); AssertIntNE(rc, 0); + /* _ex variants with caller session - NULL dev */ + rc = wolfTPM2_FirmwareUpgradeHash_ex(NULL, TPM_ALG_SHA384, NULL, 0, NULL, + 0, NULL, NULL, NULL); + AssertIntNE(rc, 0); + rc = wolfTPM2_FirmwareUpgradeRecover_ex(NULL, NULL, 0, NULL, NULL, NULL); + AssertIntNE(rc, 0); + + /* startSession == NULL must behave like the legacy call (same rc) */ + rc = wolfTPM2_FirmwareUpgradeHash(&dev, TPM_ALG_SHA384, + NULL, 0, NULL, 0, NULL, NULL); + rcEx = wolfTPM2_FirmwareUpgradeHash_ex(&dev, TPM_ALG_SHA384, + NULL, 0, NULL, 0, NULL, NULL, NULL); + AssertIntEQ(rc, rcEx); + #if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFSSL_SHA384) /* wolfTPM2_FirmwareUpgrade - NULL dev */ rc = wolfTPM2_FirmwareUpgrade(NULL, NULL, 0, NULL, NULL); AssertIntNE(rc, 0); + + /* wolfTPM2_FirmwareUpgrade_ex - NULL dev */ + rc = wolfTPM2_FirmwareUpgrade_ex(NULL, NULL, 0, NULL, NULL, NULL); + AssertIntNE(rc, 0); #endif /* !WOLFTPM2_NO_WOLFCRYPT && WOLFSSL_SHA384 */ /* ===== Test NULL/invalid parameter combinations ===== */ @@ -375,6 +394,95 @@ static void test_wolfTPM2_ST33_FirmwareUpgrade(void) #endif /* WOLFTPM_ST33 || WOLFTPM_AUTODETECT */ #endif /* WOLFTPM_FIRMWARE_UPGRADE */ +/* Argument-validation coverage for wolfTPM2_PolicyOR (host-side, no TPM). */ +static void test_wolfTPM2_PolicyOR(void) +{ + WOLFTPM2_DEV dev; + WOLFTPM2_SESSION sess; + TPML_DIGEST list; + word32 cap = (word32)(sizeof(list.digests) / sizeof(list.digests[0])); + + XMEMSET(&dev, 0, sizeof(dev)); + XMEMSET(&sess, 0, sizeof(sess)); + XMEMSET(&list, 0, sizeof(list)); + list.count = 1; + list.digests[0].size = TPM_SHA256_DIGEST_SIZE; + + /* NULL pointer arguments */ + AssertIntEQ(wolfTPM2_PolicyOR(NULL, &sess, &list), BAD_FUNC_ARG); + AssertIntEQ(wolfTPM2_PolicyOR(&dev, NULL, &list), BAD_FUNC_ARG); + AssertIntEQ(wolfTPM2_PolicyOR(&dev, &sess, NULL), BAD_FUNC_ARG); + + /* count of 0 is invalid */ + list.count = 0; + AssertIntEQ(wolfTPM2_PolicyOR(&dev, &sess, &list), BAD_FUNC_ARG); + + /* count beyond the TPML_DIGEST capacity is invalid */ + list.count = cap + 1; + AssertIntEQ(wolfTPM2_PolicyOR(&dev, &sess, &list), BAD_FUNC_ARG); + + /* a branch digest size larger than the buffer is invalid (CWE-125) */ + list.count = 1; + list.digests[0].size = (UINT16)(sizeof(list.digests[0].buffer) + 1); + AssertIntEQ(wolfTPM2_PolicyOR(&dev, &sess, &list), BAD_FUNC_ARG); + + printf("Test PolicyOR: %-40s Passed\n", "Arg Validation:"); +} + +/* Known-answer + arg-validation for wolfTPM2_PolicyCommandCodeMake (no TPM). */ +static void test_wolfTPM2_PolicyCommandCodeMake(void) +{ + int rc; + byte digest[TPM_MAX_DIGEST_SIZE]; + word32 digestSz = 0; + /* SHA2-256 PolicyCommandCode(TPM_CC_NV_Read), see examples/nvram/extend.c */ + static const byte expected[] = { + 0x47,0xce,0x30,0x32,0xd8,0xba,0xd1,0xf3, + 0x08,0x9c,0xb0,0xc0,0x90,0x88,0xde,0x43, + 0x50,0x14,0x91,0xd4,0x60,0x40,0x2b,0x90, + 0xcd,0x1b,0x7f,0xc0,0xb6,0x8c,0xa9,0x2f + }; + + AssertIntEQ(wolfTPM2_PolicyCommandCodeMake(TPM_ALG_SHA256, NULL, &digestSz, + TPM_CC_NV_Read), BAD_FUNC_ARG); + AssertIntEQ(wolfTPM2_PolicyCommandCodeMake(TPM_ALG_SHA256, digest, NULL, + TPM_CC_NV_Read), BAD_FUNC_ARG); + + rc = wolfTPM2_PolicyCommandCodeMake(TPM_ALG_SHA256, digest, &digestSz, + TPM_CC_NV_Read); + AssertIntEQ(rc, 0); + AssertIntEQ((int)digestSz, (int)sizeof(expected)); + AssertIntEQ(XMEMCMP(digest, expected, sizeof(expected)), 0); + + printf("Test PolicyCCMake:%-40s Passed\n", "Known Vector:"); +} + +/* Arg-validation for wolfTPM2_SetPrimaryPolicy (no TPM). */ +static void test_wolfTPM2_SetPrimaryPolicy(void) +{ + WOLFTPM2_DEV dev; + byte pol[TPM_MAX_DIGEST_SIZE + 4]; + + XMEMSET(&dev, 0, sizeof(dev)); + XMEMSET(pol, 0, sizeof(pol)); + + /* NULL dev */ + AssertIntEQ(wolfTPM2_SetPrimaryPolicy(NULL, TPM_RH_PLATFORM, + TPM_ALG_SHA256, pol, TPM_SHA256_DIGEST_SIZE), BAD_FUNC_ARG); + /* policy digest larger than the buffer */ + AssertIntEQ(wolfTPM2_SetPrimaryPolicy(&dev, TPM_RH_PLATFORM, + TPM_ALG_SHA256, pol, (word32)sizeof(pol)), BAD_FUNC_ARG); + + printf("Test SetPrimPol: %-40s Passed\n", "Arg Validation:"); +} + +/* NULL-dev handling for wolfTPM2_IsAlgSupported (no TPM). */ +static void test_wolfTPM2_IsAlgSupported(void) +{ + AssertIntEQ(wolfTPM2_IsAlgSupported(NULL, TPM_ALG_SHA256), 0); + printf("Test IsAlgSupp: %-40s Passed\n", "NULL dev:"); +} + static void test_wolfTPM2_GetRandom(void) { int rc; @@ -7515,6 +7623,10 @@ int unit_tests(int argc, char *argv[]) test_wolfTPM2_ST33_FirmwareUpgrade(); #endif #endif + test_wolfTPM2_PolicyOR(); + test_wolfTPM2_PolicyCommandCodeMake(); + test_wolfTPM2_SetPrimaryPolicy(); + test_wolfTPM2_IsAlgSupported(); #if defined(WOLFTPM_MLDSA) && defined(WOLFTPM_MLKEM) /* Run non-TPM-dependent tests first */ test_wolfTPM2_PQC_KeyTemplates(); diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 4f40378b1..7c624f913 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -399,6 +399,25 @@ WOLFTPM_API int wolfTPM2_SelfTest(WOLFTPM2_DEV* dev); */ WOLFTPM_API int wolfTPM2_GetCapabilities(WOLFTPM2_DEV* dev, WOLFTPM2_CAPS* caps); +/*! + \ingroup wolfTPM2_Wrappers + + \brief Report whether the TPM implements a given algorithm + + \note Queries TPM_CAP_ALGS. Useful to skip a hash the TPM does not support + (for example SHA2-512 on parts limited to SHA2-256/384) before starting + a session with it. + + \return 1 if the algorithm is supported + \return 0 if it is not supported, dev is NULL, or the query fails + + \param dev pointer to a TPM2_DEV struct + \param alg the algorithm identifier to test (for example TPM_ALG_SHA512) + + \sa wolfTPM2_GetCapabilities +*/ +WOLFTPM_API int wolfTPM2_IsAlgSupported(WOLFTPM2_DEV* dev, TPM_ALG_ID alg); + /*! \ingroup wolfTPM2_Wrappers \brief Gets a list of handles @@ -4875,6 +4894,31 @@ WOLFTPM_API int wolfTPM2_PolicyPCRMake(TPM_ALG_ID pcrAlg, byte* pcrArray, word32 pcrArraySz, const byte* pcrDigest, word32 pcrDigestSz, byte* digest, word32* digestSz); +/*! + \ingroup wolfTPM2_Wrappers + + \brief Compute the policy digest for PolicyCommandCode on a fresh session + + \note policyDigest = hash(zeroDigest || TPM_CC_PolicyCommandCode || cc). The + digest buffer is written and *digestSz set to the hash size; the caller + does not need to pre-initialize them. Mirrors the running digest of a + new policy session after wolfTPM2_PolicyCommandCode. + + \return TPM_RC_SUCCESS: successful + \return BAD_FUNC_ARG: NULL digest/digestSz or unsupported hashAlg + + \param hashAlg hash algorithm for the policy digest + \param digest output policy digest buffer (>= hash size) + \param digestSz output digest size + \param cc the command code to bind (for example TPM_CC_NV_Read) + + \sa wolfTPM2_PolicyCommandCode + \sa wolfTPM2_PolicyHash + \sa wolfTPM2_PolicyPCRMake +*/ +WOLFTPM_API int wolfTPM2_PolicyCommandCodeMake(TPM_ALG_ID hashAlg, + byte* digest, word32* digestSz, TPM_CC cc); + /*! \ingroup wolfTPM2_Wrappers @@ -4979,6 +5023,58 @@ WOLFTPM_API int wolfTPM2_PolicyAuthValue(WOLFTPM2_DEV* dev, WOLFTPM_API int wolfTPM2_PolicyCommandCode(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, TPM_CC cc); +/*! + \ingroup wolfTPM2_Wrappers + + \brief Wrapper for satisfying a policy session with a compound OR of digests + + \note The digest list is hash-agnostic (each branch carries its own size), + so it supports SHA2-256 through SHA2-512 policy branches. The number of + branches (pHashList->count) must be between 1 and the TPML_DIGEST + capacity (the digests[] array length), and each branch's size must not + exceed the digest buffer length; branches beyond count are ignored. + + \return TPM_RC_SUCCESS: successful + \return BAD_FUNC_ARG: bad pointer, count out of range, or a branch size that + exceeds the digest buffer + + \param dev pointer to a TPM2_DEV struct + \param tpmSession pointer to a WOLFTPM2_SESSION struct used with wolfTPM2_StartSession and wolfTPM2_SetAuthSession + \param pHashList list of pre-computed policy branch digests to OR together + + \sa wolfTPM2_PolicyPCR + \sa wolfTPM2_PolicyAuthorize + \sa wolfTPM2_GetPolicyDigest +*/ +WOLFTPM_API int wolfTPM2_PolicyOR(WOLFTPM2_DEV* dev, + WOLFTPM2_SESSION* tpmSession, const TPML_DIGEST* pHashList); + +/*! + \ingroup wolfTPM2_Wrappers + + \brief Set (or clear) the authPolicy of a hierarchy + + \note Wraps TPM2_SetPrimaryPolicy for owner/endorsement/platform/lockout. + Pass authPolicy=NULL, authPolicySz=0 and hashAlg=TPM_ALG_NULL to clear + an existing policy. The command itself is authorized by the hierarchy's + current auth (set it on the device's active session beforehand). + + \return TPM_RC_SUCCESS: successful + \return BAD_FUNC_ARG: NULL dev or authPolicySz exceeds the digest buffer + + \param dev pointer to a TPM2_DEV struct + \param authHandle the hierarchy (for example TPM_RH_PLATFORM) + \param hashAlg the policy digest hash algorithm (TPM_ALG_NULL to clear) + \param authPolicy the policy digest to set (NULL to clear) + \param authPolicySz size of the policy digest (0 to clear) + + \sa wolfTPM2_PolicyOR + \sa wolfTPM2_GetPolicyDigest +*/ +WOLFTPM_API int wolfTPM2_SetPrimaryPolicy(WOLFTPM2_DEV* dev, + TPMI_RH_HIERARCHY_AUTH authHandle, TPM_ALG_ID hashAlg, + const byte* authPolicy, word32 authPolicySz); + /* Pre-provisioned IAK and IDevID key/cert from TPM vendor */ /* Tested with ST33KTPM devices */ @@ -5111,6 +5207,45 @@ WOLFTPM_API int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, uint8_t* manifest, uint32_t manifest_sz, wolfTPM2FwDataCb cb, void* cb_ctx); +/*! + \ingroup wolfTPM2_Wrappers + \brief Perform TPM firmware upgrade using a caller-supplied authorization session + \note Identical to wolfTPM2_FirmwareUpgradeHash except the caller controls how + the firmware-start command is authorized against the platform hierarchy. + \note When startSession is NULL this behaves exactly like + wolfTPM2_FirmwareUpgradeHash (library-managed platform authorization). + \note When startSession is non-NULL the caller is responsible for having + satisfied the platform authPolicy on that session (for example via + wolfTPM2_PolicyPCR / wolfTPM2_PolicyAuthorize / wolfTPM2_PolicyOR using + SHA2-256 or SHA2-512). For Infineon the platform primary policy is left + untouched (the caller provisions it); for ST33 the session replaces the + default TPM_RS_PW password authorization. + + \return TPM_RC_SUCCESS: successful + \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) + \return BAD_FUNC_ARG: check the provided arguments + + \param dev pointer to a TPM2_DEV struct + \param hashAlg hash algorithm to use (TPM_ALG_SHA384 or TPM_ALG_SHA512) + \param manifest_hash buffer to store computed manifest hash + \param manifest_hash_sz size of manifest hash buffer + \param manifest pointer to firmware manifest data + \param manifest_sz size of firmware manifest + \param cb callback function for firmware data access + \param cb_ctx context pointer passed to callback + \param startSession optional caller-satisfied session authorizing the + firmware-start command (NULL for library-managed authorization) + + \sa wolfTPM2_FirmwareUpgradeHash + \sa wolfTPM2_PolicyOR + \sa wolfTPM2_StartSession_ex +*/ +WOLFTPM_API int wolfTPM2_FirmwareUpgradeHash_ex(WOLFTPM2_DEV* dev, + TPM_ALG_ID hashAlg, /* Can use SHA2-384 or SHA2-512 for manifest hash */ + uint8_t* manifest_hash, uint32_t manifest_hash_sz, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession); + #ifndef WOLFTPM2_NO_WOLFCRYPT /*! \ingroup wolfTPM2_Wrappers @@ -5138,6 +5273,30 @@ WOLFTPM_API int wolfTPM2_FirmwareUpgradeHash(WOLFTPM2_DEV* dev, WOLFTPM_API int wolfTPM2_FirmwareUpgrade(WOLFTPM2_DEV* dev, uint8_t* manifest, uint32_t manifest_sz, wolfTPM2FwDataCb cb, void* cb_ctx); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Perform TPM firmware upgrade using a caller-supplied authorization session + \note Same as wolfTPM2_FirmwareUpgrade but the caller controls how the + firmware-start command is authorized (see wolfTPM2_FirmwareUpgradeHash_ex). + startSession NULL preserves the default library-managed behavior. + + \return TPM_RC_SUCCESS: successful + \return NOT_COMPILED_IN: wolfSSL not built with WOLFSSL_SHA384 + + \param dev pointer to a TPM2_DEV struct + \param manifest pointer to firmware manifest data + \param manifest_sz size of firmware manifest + \param cb callback function for firmware data access + \param cb_ctx context pointer passed to callback + \param startSession optional caller-satisfied session (NULL for default) + + \sa wolfTPM2_FirmwareUpgrade + \sa wolfTPM2_FirmwareUpgradeHash_ex +*/ +WOLFTPM_API int wolfTPM2_FirmwareUpgrade_ex(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession); #endif /* !WOLFTPM2_NO_WOLFCRYPT */ /*! @@ -5162,6 +5321,30 @@ WOLFTPM_API int wolfTPM2_FirmwareUpgradeRecover(WOLFTPM2_DEV* dev, uint8_t* manifest, uint32_t manifest_sz, wolfTPM2FwDataCb cb, void* cb_ctx); +/*! + \ingroup wolfTPM2_Wrappers + \brief Recover from a failed firmware upgrade using a caller-supplied session + \note Same as wolfTPM2_FirmwareUpgradeRecover but with caller-controlled + authorization (see wolfTPM2_FirmwareUpgradeHash_ex). startSession NULL + preserves the default library-managed behavior. + + \return TPM_RC_SUCCESS: successful + \return BAD_FUNC_ARG: check the provided arguments + + \param dev pointer to a TPM2_DEV struct + \param manifest pointer to firmware manifest data + \param manifest_sz size of firmware manifest + \param cb callback function for firmware data access + \param cb_ctx context pointer passed to callback + \param startSession optional caller-satisfied session (NULL for default) + + \sa wolfTPM2_FirmwareUpgradeRecover + \sa wolfTPM2_FirmwareUpgradeHash_ex +*/ +WOLFTPM_API int wolfTPM2_FirmwareUpgradeRecover_ex(WOLFTPM2_DEV* dev, + uint8_t* manifest, uint32_t manifest_sz, + wolfTPM2FwDataCb cb, void* cb_ctx, WOLFTPM2_SESSION* startSession); + /*! \ingroup wolfTPM2_Wrappers \brief Cancel ongoing TPM firmware upgrade