From 17097f4771ceee21127a46d7f297cfba829f1a2d Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 21 Oct 2026 23:33:05 -0700 Subject: [PATCH] nv: support owner/platform hierarchy auth in NV read/write wrappers --- .gitignore | 1 + CMakeLists.txt | 1 + examples/README.md | 12 ++ examples/nvram/include.am | 11 +- examples/nvram/nvauth.c | 394 ++++++++++++++++++++++++++++++++++++++ examples/nvram/nvram.h | 1 + examples/run_examples.sh | 19 ++ examples/tpm_test.h | 1 + src/tpm2_wrap.c | 108 ++++++++--- tests/unit_tests.c | 221 +++++++++++++++++++++ wolftpm/tpm2_wrap.h | 9 + 11 files changed, 753 insertions(+), 25 deletions(-) create mode 100644 examples/nvram/nvauth.c diff --git a/.gitignore b/.gitignore index d40a0b34a..4220a7dae 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ examples/nvram/read examples/nvram/counter examples/nvram/policy_nv examples/nvram/seal_nv +examples/nvram/nvauth examples/gpio/gpio_config examples/gpio/gpio_set examples/gpio/gpio_read diff --git a/CMakeLists.txt b/CMakeLists.txt index 987184c19..1f4ca39eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -957,6 +957,7 @@ if (WOLFTPM_EXAMPLES AND BUILD_WOLFTPM_LIB) add_tpm_example(read nvram/read.c) add_tpm_example(store nvram/store.c) add_tpm_example(seal_nv nvram/seal_nv.c) + add_tpm_example(nvauth nvram/nvauth.c) add_tpm_example(extend pcr/extend.c) add_tpm_example(policy_sign pcr/policy_sign.c) add_tpm_example(policy pcr/policy.c) diff --git a/examples/README.md b/examples/README.md index 6fda0cdc5..4c6791bdd 100644 --- a/examples/README.md +++ b/examples/README.md @@ -431,6 +431,18 @@ Extraction of key from NVRAM at index 0x1800202 succeeded After successful key extraction using "read", the NV Index is destroyed. Therefore, to use "read" again, the "store" example must be run again as well. +### NV Index with Owner Authorization + +The `nvram/nvauth` example creates an NV Index that can be read without a password (`TPMA_NV_AUTHREAD` with an empty NV Index auth), while write and delete require the owner hierarchy authorization (`TPMA_NV_OWNERWRITE`). For an owner or platform authorized index set `nv.handle.hndl` to `TPM_RH_OWNER` or `TPM_RH_PLATFORM` and `nv.handle.auth` to that hierarchy auth after `wolfTPM2_NVOpen`, then use `wolfTPM2_NVWriteAuth` or `wolfTPM2_NVReadAuth`. + +With `-policy` the write uses `TPMA_NV_POLICYWRITE` with a PolicyCommandCode(NV_Write) + PolicySecret(owner) policy, satisfied by the caller and passed to `wolfTPM2_NVWriteAuthPolicy` with no PCR's. + +Deleting an NV Index (`TPM2_NV_UndefineSpace`) always requires the owner (or platform) auth. The owner auth can be changed with `TPM2_HierarchyChangeAuth` using only the current owner auth; the index is bound to the hierarchy, not its auth value, so it keeps working. `-rotate=` demonstrates this and restores the original owner auth. + +```sh +./examples/nvram/nvauth [-ownerauth=] [-rotate=] [-policy] [-aes/-xor] +``` + ## Seal / Unseal TPM 2.0 can protect secrets using a standard Seal/Unseal procedure. Seal can be created using a TPM 2.0 key or against a set of PCR values. Note: Secret data sealed in a key is limited to a maximum size of 128 bytes. diff --git a/examples/nvram/include.am b/examples/nvram/include.am index 7e4063437..862750469 100644 --- a/examples/nvram/include.am +++ b/examples/nvram/include.am @@ -39,6 +39,11 @@ examples_nvram_seal_nv_SOURCES = examples/nvram/seal_nv.c \ examples/tpm_test_keys.c examples_nvram_seal_nv_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) examples_nvram_seal_nv_DEPENDENCIES = src/libwolftpm.la + +noinst_PROGRAMS += examples/nvram/nvauth +examples_nvram_nvauth_SOURCES = examples/nvram/nvauth.c +examples_nvram_nvauth_LDADD = src/libwolftpm.la $(LIB_STATIC_ADD) +examples_nvram_nvauth_DEPENDENCIES = src/libwolftpm.la endif example_nvramdir = $(exampledir)/nvram @@ -48,11 +53,13 @@ dist_example_nvram_DATA = \ examples/nvram/counter.c \ examples/nvram/policy_nv.c \ examples/nvram/extend.c \ - examples/nvram/seal_nv.c + examples/nvram/seal_nv.c \ + examples/nvram/nvauth.c DISTCLEANFILES+= examples/nvram/.libs/store \ examples/nvram/.libs/read \ examples/nvram/.libs/counter \ examples/nvram/.libs/policy_nv \ examples/nvram/.libs/extend \ - examples/nvram/.libs/seal_nv + examples/nvram/.libs/seal_nv \ + examples/nvram/.libs/nvauth diff --git a/examples/nvram/nvauth.c b/examples/nvram/nvauth.c new file mode 100644 index 000000000..8edd8360b --- /dev/null +++ b/examples/nvram/nvauth.c @@ -0,0 +1,394 @@ +/* nvauth.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 + */ + +/* Example for an NV Index that can be read without a password, while write + * and delete require the owner hierarchy authorization. + * + * Read uses TPMA_NV_AUTHREAD with an empty NV Index auth. + * Write uses TPMA_NV_OWNERWRITE (owner password), or with -policy + * TPMA_NV_POLICYWRITE with PolicyCommandCode(NV_Write) + PolicySecret(owner). + * Delete (NV_UndefineSpace) always requires the owner hierarchy auth. + * + * The owner auth can be rotated with TPM2_HierarchyChangeAuth using only the + * current owner auth. The NV Index is bound to the owner hierarchy handle, not + * its auth value, so it is not affected by rotation (see -rotate). + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include +#include + +/******************************************************************************/ +/* --- BEGIN TPM NVRAM Owner Auth Example -- */ +/******************************************************************************/ +static void usage(void) +{ + printf("Expected usage:\n"); + printf("./examples/nvram/nvauth [-ownerauth=] [-rotate=] " + "[-policy] [-aes/-xor]\n"); + printf("* -ownerauth=: Current owner hierarchy auth (default empty)\n"); + printf("* -rotate=: Change the owner auth after the first write, " + "write again, then restore it\n"); + printf("* -policy: Use a policy (PolicySecret owner) for write instead of " + "OWNERWRITE\n"); + printf("* -aes/xor: Use Parameter Encryption\n"); +} + +/* volatile so the compiler cannot drop the clearing of auth values */ +static void ForceZero(void* mem, word32 len) +{ + volatile byte* p = (volatile byte*)mem; + while (len--) { + *p++ = 0; + } +} + +static int SetOwnerAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* owner, + const char* newAuth) +{ + int rc; + HierarchyChangeAuth_In in; + + wolfTPM2_SetAuthHandle(dev, 0, owner); + + XMEMSET(&in, 0, sizeof(in)); + in.authHandle = TPM_RH_OWNER; + in.newAuth.size = (UINT16)XSTRLEN(newAuth); + XMEMCPY(in.newAuth.buffer, newAuth, in.newAuth.size); + rc = TPM2_HierarchyChangeAuth(&in); + if (rc == TPM_RC_SUCCESS) { + owner->auth.size = in.newAuth.size; + XMEMCPY(owner->auth.buffer, in.newAuth.buffer, owner->auth.size); + printf("Owner auth changed (%d bytes)\n", owner->auth.size); + } + ForceZero(&in, sizeof(in)); + return rc; +} + +#ifndef WOLFTPM2_NO_WOLFCRYPT +/* policyDigest = PolicyCommandCode(TPM_CC_NV_Write) + PolicySecret(owner) */ +static int BuildWritePolicy(byte* digest, word32* digestSz) +{ + int rc; + byte ownerName[4]; + + rc = wolfTPM2_PolicyCommandCodeMake(WOLFTPM2_WRAP_DIGEST, digest, digestSz, + TPM_CC_NV_Write); + if (rc == 0) { + /* Name of a permanent handle is the handle value (big-endian) */ + ownerName[0] = (byte)((TPM_RH_OWNER >> 24) & 0xFF); + ownerName[1] = (byte)((TPM_RH_OWNER >> 16) & 0xFF); + ownerName[2] = (byte)((TPM_RH_OWNER >> 8) & 0xFF); + ownerName[3] = (byte)(TPM_RH_OWNER & 0xFF); + rc = wolfTPM2_PolicyHash(WOLFTPM2_WRAP_DIGEST, digest, digestSz, + TPM_CC_PolicySecret, ownerName, sizeof(ownerName)); + } + if (rc == 0) { + /* empty policyRef */ + rc = wolfTPM2_PolicyRefMake(WOLFTPM2_WRAP_DIGEST, digest, digestSz, + NULL, 0); + } + return rc; +} +#endif + +static int WriteData(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* owner, word32 nvIndex, + int usePolicy, const char* data) +{ + int rc; + WOLFTPM2_NV nv; + word32 dataSz = (word32)XSTRLEN(data); + + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVOpen(dev, &nv, nvIndex, NULL, 0); + if (rc != TPM_RC_SUCCESS) { + return rc; + } + + if (!usePolicy) { + /* authHandle is the owner hierarchy, not the NV Index */ + nv.handle.hndl = TPM_RH_OWNER; + XMEMCPY(&nv.handle.auth, &owner->auth, sizeof(nv.handle.auth)); + rc = wolfTPM2_NVWriteAuth(dev, &nv, nvIndex, (byte*)data, dataSz, 0); + } + else { + WOLFTPM2_SESSION policySession; + PolicySecret_In secIn; + PolicySecret_Out secOut; + + rc = wolfTPM2_StartSession(dev, &policySession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + if (rc != TPM_RC_SUCCESS) { + return rc; + } + /* Must match the order used in BuildWritePolicy */ + rc = wolfTPM2_PolicyCommandCode(dev, &policySession, TPM_CC_NV_Write); + if (rc == TPM_RC_SUCCESS) { + /* PolicySecret is authorized with the owner auth (slot 0) */ + wolfTPM2_SetAuthHandle(dev, 0, owner); + XMEMSET(&secIn, 0, sizeof(secIn)); + secIn.authHandle = TPM_RH_OWNER; + secIn.policySession = policySession.handle.hndl; + rc = TPM2_PolicySecret(&secIn, &secOut); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_SetAuthSession(dev, 0, &policySession, + TPMA_SESSION_continueSession); + } + if (rc == TPM_RC_SUCCESS) { + /* No PCR's, the policy session is already satisfied */ + rc = wolfTPM2_NVWriteAuthPolicy(dev, &policySession, TPM_ALG_NULL, + NULL, 0, &nv, nvIndex, (byte*)data, dataSz, 0); + } + wolfTPM2_SetAuthPassword(dev, 0, NULL); + wolfTPM2_UnloadHandle(dev, &policySession.handle); + } + if (rc == TPM_RC_SUCCESS) { + printf("Wrote %d bytes to NV index 0x%x\n", dataSz, nvIndex); + } + ForceZero(&nv, sizeof(nv)); + return rc; +} + +static int ReadData(WOLFTPM2_DEV* dev, word32 nvIndex, const char* expected) +{ + int rc; + WOLFTPM2_NV nv; + byte buf[64]; + word32 bufSz = (word32)XSTRLEN(expected); + + if (bufSz >= sizeof(buf)) { + return BUFFER_E; + } + /* No password: TPMA_NV_AUTHREAD with an empty NV Index auth */ + wolfTPM2_SetAuthPassword(dev, 0, NULL); + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVOpen(dev, &nv, nvIndex, NULL, 0); + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_NVReadAuth(dev, &nv, nvIndex, buf, &bufSz, 0); + } + if (rc == TPM_RC_SUCCESS) { + buf[bufSz] = '\0'; + printf("Read %d bytes from NV index 0x%x (no auth): %s\n", + bufSz, nvIndex, buf); + if (XSTRCMP((char*)buf, expected) != 0) { + printf("NV data mismatch\n"); + rc = TPM_RC_FAILURE; + } + } + return rc; +} + +int TPM2_NVRAM_Auth_Example(void* userCtx, int argc, char *argv[]) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_SESSION tpmSession; + WOLFTPM2_HANDLE owner; + WOLFTPM2_NV nv; + word32 nvIndex = TPM2_DEMO_NVRAM_AUTH_INDEX; + word32 nvAttributes; + const char* ownerAuthStr = ""; + const char* rotateAuthStr = NULL; + int usePolicy = 0; + int rotated = 0; + int paramEncAlg = TPM_ALG_NULL; + byte policyDigest[TPM_MAX_DIGEST_SIZE]; + word32 policyDigestSz = 0; + + if (argc >= 2) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + while (argc > 1) { + if (XSTRNCMP(argv[argc-1], "-ownerauth=", + XSTRLEN("-ownerauth=")) == 0) { + ownerAuthStr = argv[argc-1] + XSTRLEN("-ownerauth="); + } + else if (XSTRNCMP(argv[argc-1], "-rotate=", + XSTRLEN("-rotate=")) == 0) { + rotateAuthStr = argv[argc-1] + XSTRLEN("-rotate="); + } + else if (XSTRCMP(argv[argc-1], "-policy") == 0) { + usePolicy = 1; + } + else if (XSTRCMP(argv[argc-1], "-aes") == 0) { + paramEncAlg = TPM_ALG_CFB; + } + else if (XSTRCMP(argv[argc-1], "-xor") == 0) { + paramEncAlg = TPM_ALG_XOR; + } + else { + printf("Warning: Unrecognized option: %s\n", argv[argc-1]); + } + argc--; + } + if (XSTRLEN(ownerAuthStr) > sizeof(owner.auth.buffer) || + (rotateAuthStr != NULL && + XSTRLEN(rotateAuthStr) > sizeof(owner.auth.buffer))) { + printf("Owner auth too long\n"); + return BAD_FUNC_ARG; + } +#ifdef WOLFTPM2_NO_WOLFCRYPT + if (usePolicy) { + printf("Policy mode requires wolfCrypt\n"); + return NOT_COMPILED_IN; + } +#endif + + printf("NV Index 0x%x: read without auth, %s write, owner auth delete\n", + nvIndex, usePolicy ? "policy (PolicySecret owner)" : "owner auth"); + printf("\tParameter Encryption: %s\n", TPM2_GetAlgName(paramEncAlg)); + + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); + XMEMSET(&owner, 0, sizeof(owner)); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != TPM_RC_SUCCESS) { + printf("\nwolfTPM2_Init failed\n"); + return rc; + } + + owner.hndl = TPM_RH_OWNER; + owner.auth.size = (UINT16)XSTRLEN(ownerAuthStr); + XMEMCPY(owner.auth.buffer, ownerAuthStr, owner.auth.size); + + if (paramEncAlg != TPM_ALG_NULL) { + /* Start an unbound, unsalted session for parameter encryption */ + rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, NULL, + TPM_SE_HMAC, paramEncAlg); + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_SetAuthSession(&dev, 1, &tpmSession, + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | + TPMA_SESSION_continueSession)); + } + if (rc != TPM_RC_SUCCESS) goto exit; + } + + nvAttributes = (TPMA_NV_AUTHREAD | TPMA_NV_NO_DA | TPM_NT_ORDINARY); + if (usePolicy) { + #ifndef WOLFTPM2_NO_WOLFCRYPT + policyDigestSz = (word32)sizeof(policyDigest); + rc = BuildWritePolicy(policyDigest, &policyDigestSz); + if (rc != 0) goto exit; + #endif + nvAttributes |= TPMA_NV_POLICYWRITE; + } + else { + nvAttributes |= TPMA_NV_OWNERWRITE; + } + + /* Create the NV Index with an empty auth, re-creating any prior one */ + wolfTPM2_SetAuthHandle(&dev, 0, &owner); + rc = wolfTPM2_NVCreateAuthPolicy(&dev, &owner, &nv, nvIndex, nvAttributes, + 64, NULL, 0, policyDigest, (int)policyDigestSz); + if (rc == TPM_RC_NV_DEFINED) { + rc = wolfTPM2_NVDeleteAuth(&dev, &owner, nvIndex); + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_NVCreateAuthPolicy(&dev, &owner, &nv, nvIndex, + nvAttributes, 64, NULL, 0, policyDigest, (int)policyDigestSz); + } + } + if (rc != TPM_RC_SUCCESS) goto exit; + printf("Created NV index 0x%x, attributes 0x%x\n", nvIndex, nvAttributes); + + rc = WriteData(&dev, &owner, nvIndex, usePolicy, "first"); + if (rc == TPM_RC_SUCCESS) { + rc = ReadData(&dev, nvIndex, "first"); + } + if (rc == TPM_RC_SUCCESS && rotateAuthStr != NULL) { + rc = SetOwnerAuth(&dev, &owner, rotateAuthStr); + if (rc == TPM_RC_SUCCESS) { + rotated = 1; + rc = WriteData(&dev, &owner, nvIndex, usePolicy, "rotated"); + } + if (rc == TPM_RC_SUCCESS) { + rc = ReadData(&dev, nvIndex, "rotated"); + } + } + if (rc == TPM_RC_SUCCESS) { + wolfTPM2_SetAuthHandle(&dev, 0, &owner); + rc = wolfTPM2_NVDeleteAuth(&dev, &owner, nvIndex); + if (rc == TPM_RC_SUCCESS) { + printf("Deleted NV index 0x%x (owner auth)\n", nvIndex); + } + } + +exit: + + if (rotated) { + /* restore the original owner auth */ + int rcRestore = SetOwnerAuth(&dev, &owner, ownerAuthStr); + if (rcRestore != TPM_RC_SUCCESS) { + printf("Owner auth restore failed 0x%x: %s\n", rcRestore, + wolfTPM2_GetRCString(rcRestore)); + if (rc == TPM_RC_SUCCESS) { + rc = rcRestore; + } + } + } + + if (rc != 0) { + printf("\nFailure 0x%x: %s\n\n", rc, wolfTPM2_GetRCString(rc)); + } + + ForceZero(&owner, sizeof(owner)); + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM NVRAM Owner Auth Example -- */ +/******************************************************************************/ +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char *argv[]) +{ + int rc = NOT_COMPILED_IN; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_NVRAM_Auth_Example(NULL, argc, argv); +#else + printf("NVRAM code not compiled in\n"); + (void)argc; + (void)argv; +#endif + + return rc; +} +#endif diff --git a/examples/nvram/nvram.h b/examples/nvram/nvram.h index d2f9fc495..68f5fe3f7 100644 --- a/examples/nvram/nvram.h +++ b/examples/nvram/nvram.h @@ -32,6 +32,7 @@ int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[]); int TPM2_NVRAM_PolicyNV_Example(void* userCtx, int argc, char *argv[]); int TPM2_NVRAM_SealNV_Example(void* userCtx, int argc, char *argv[]); int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]); +int TPM2_NVRAM_Auth_Example(void* userCtx, int argc, char *argv[]); #ifdef __cplusplus } /* extern "C" */ diff --git a/examples/run_examples.sh b/examples/run_examples.sh index b18a3a9e4..8c88ad5a5 100755 --- a/examples/run_examples.sh +++ b/examples/run_examples.sh @@ -596,6 +596,25 @@ RESULT=$? RESULT=$? [ $RESULT -ne 0 ] && echo -e "nv policy nv aes failed! $RESULT" && exit 1 +# NV read without auth, write/delete with owner auth +./examples/nvram/nvauth >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "nv auth failed! $RESULT" && exit 1 +./examples/nvram/nvauth -rotate=ownerpw >> $TPMPWD/run.out 2>&1 +RESULT=$? +[ $RESULT -ne 0 ] && echo -e "nv auth rotate failed! $RESULT" && exit 1 +if [ $WOLFCRYPT_ENABLE -eq 1 ]; then + ./examples/nvram/nvauth -aes -rotate=ownerpw >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "nv auth aes failed! $RESULT" && exit 1 + ./examples/nvram/nvauth -policy >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "nv auth policy failed! $RESULT" && exit 1 + ./examples/nvram/nvauth -policy -xor -rotate=ownerpw >> $TPMPWD/run.out 2>&1 + RESULT=$? + [ $RESULT -ne 0 ] && echo -e "nv auth policy xor failed! $RESULT" && exit 1 +fi + # CSR Tests ./examples/keygen/keygen rsa_test_blob.raw -rsa -t >> $TPMPWD/run.out 2>&1 diff --git a/examples/tpm_test.h b/examples/tpm_test.h index 765dfaac6..d05452ae2 100644 --- a/examples/tpm_test.h +++ b/examples/tpm_test.h @@ -46,6 +46,7 @@ #define TPM2_DEMO_NV_TEST_AUTH_INDEX 0x01800201 #define TPM2_DEMO_NVRAM_STORE_INDEX 0x01800202 #define TPM2_DEMO_NV_TEST_CHUNKED_INDEX 0x01800205 +#define TPM2_DEMO_NVRAM_AUTH_INDEX 0x01800206 #define TPM2_DEMO_NVRAM_EXTEND_INDEX 0x01000200 #define TPM2_DEMO_NV_TEST_SIZE MAX_DIGEST_BUFFER /* max size on Infineon SLB9670 is 1664 */ #define TPM2_DEMO_NV_COUNTER_INDEX 0x01800300 diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 59b480a0a..cbf0b7ea9 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -7741,6 +7741,34 @@ int wolfTPM2_UnloadHandle(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle) return TPM_RC_SUCCESS; } +/* Read the NV Index public area and compute its Name */ +static int wolfTPM2_NVComputeName(WOLFTPM2_DEV* dev, word32 nvIndex, + TPM2B_NAME* name, TPMA_NV* attributes) +{ + int rc; + TPMS_NV_PUBLIC nvPublic; + + rc = wolfTPM2_NVReadPublic(dev, nvIndex, &nvPublic); + if (rc == TPM_RC_SUCCESS) { + if (attributes != NULL) { + *attributes = nvPublic.attributes; + } + #ifndef WOLFTPM2_NO_WOLFCRYPT + rc = TPM2_HashNvPublic(&nvPublic, (byte*)&name->name, &name->size); + #else + (void)name; + #endif + } + return rc; +} + +/* NV read/write authHandle may be the owner or platform hierarchy instead of + * the NV Index (TPMA_NV_OWNERWRITE/PPWRITE/OWNERREAD/PPREAD) */ +static int wolfTPM2_NVIsHierarchyAuth(TPM_HANDLE authHandle) +{ + return (authHandle == TPM_RH_OWNER || authHandle == TPM_RH_PLATFORM); +} + /* nv is the populated handle and auth */ /* auth and authSz are optional NV authentication */ /* authPolicy and authPolicySz are optional policy digest */ @@ -7908,6 +7936,7 @@ static int wolfTPM2_NVWriteData(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, { int rc = TPM_RC_SUCCESS; word32 pos = 0, towrite; + int hierAuth; union { NV_Write_In write; NV_Extend_In extend; @@ -7916,14 +7945,32 @@ static int wolfTPM2_NVWriteData(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, if (dev == NULL || nv == NULL || dataBuf == NULL) { return BAD_FUNC_ARG; } + if ((pcrArray == NULL) != (pcrArraySz == 0)) { + return BAD_FUNC_ARG; + } + /* A caller built policy (no PCR) is consumed by the first chunk */ + if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl) + && pcrArray == NULL && dataSz > MAX_NV_BUFFER_SIZE) { + return BUFFER_E; + } + hierAuth = wolfTPM2_NVIsHierarchyAuth(nv->handle.hndl); while (dataSz > 0) { towrite = dataSz; if (towrite > MAX_NV_BUFFER_SIZE) towrite = MAX_NV_BUFFER_SIZE; + if (hierAuth) { + /* Keep the hierarchy authHandle, only refresh the NV Index Name */ + if (pos == 0 || (nv->attributes & TPMA_NV_WRITTEN) == 0) { + rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name, + &nv->attributes); + if (rc != 0) + break; + } + } /* Refresh for the first policy chunk and until NV_WRITTEN is cached. */ - if (!nv->handle.nameLoaded || + else if (!nv->handle.nameLoaded || nv->handle.hndl != (TPM_HANDLE)nvIndex || (nv->attributes & TPMA_NV_WRITTEN) == 0 || (pos == 0 && tpmSession != NULL && @@ -7936,10 +7983,12 @@ static int wolfTPM2_NVWriteData(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)) { /* PCR resets after each call for TPMA_SESSION_continueSession */ - rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl, - pcrAlg, pcrArray, pcrArraySz); - if (rc != TPM_RC_SUCCESS) - break; + if (pcrArray != NULL) { + rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl, + pcrAlg, pcrArray, pcrArraySz); + if (rc != TPM_RC_SUCCESS) + break; + } /* Set policy session while saving nonceTPM */ wolfTPM2_SetSessionHandle(dev, 0, tpmSession); @@ -8037,6 +8086,7 @@ int wolfTPM2_NVReadAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, { int rc = TPM_RC_SUCCESS; word32 pos = 0, toread, dataSz; + int hierAuth; NV_Read_In in; NV_Read_Out out; @@ -8045,13 +8095,32 @@ int wolfTPM2_NVReadAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, } dataSz = *pDataSz; + if ((pcrArray == NULL) != (pcrArraySz == 0)) { + return BAD_FUNC_ARG; + } + /* A caller built policy (no PCR) is consumed by the first chunk */ + if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl) + && pcrArray == NULL && dataSz > MAX_NV_BUFFER_SIZE) { + return BUFFER_E; + } + hierAuth = wolfTPM2_NVIsHierarchyAuth(nv->handle.hndl); + while (dataSz > 0) { toread = dataSz; if (toread > MAX_NV_BUFFER_SIZE) toread = MAX_NV_BUFFER_SIZE; + if (hierAuth) { + /* Keep the hierarchy authHandle, only refresh the NV Index Name */ + if (pos == 0) { + rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name, + &nv->attributes); + if (rc != 0) + break; + } + } /* Make sure the name is computed for the handle. */ - if (!nv->handle.nameLoaded || (pos == 0 && tpmSession != NULL + else if (!nv->handle.nameLoaded || (pos == 0 && tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl))) { rc = wolfTPM2_NVOpen(dev, nv, nvIndex, NULL, 0); if (rc != 0) @@ -8061,10 +8130,12 @@ int wolfTPM2_NVReadAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* tpmSession, if (tpmSession != NULL && TPM2_IS_POLICY_SESSION(tpmSession->handle.hndl)) { /* PCR resets after each call for TPMA_SESSION_continueSession */ - rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl, - pcrAlg, pcrArray, pcrArraySz); - if (rc != 0) - break; + if (pcrArray != NULL) { + rc = wolfTPM2_PolicyPCR(dev, tpmSession->handle.hndl, + pcrAlg, pcrArray, pcrArraySz); + if (rc != 0) + break; + } /* Set policy session while saving nonceTPM */ wolfTPM2_SetSessionHandle(dev, 0, tpmSession); @@ -8201,7 +8272,6 @@ int wolfTPM2_NVOpen(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, word32 nvIndex, const byte* auth, word32 authSz) { int rc = TPM_RC_SUCCESS; - TPMS_NV_PUBLIC nvPublic; TPM2B_AUTH newAuth; if (dev == NULL || nv == NULL || authSz > sizeof(nv->handle.auth.buffer)) { @@ -8217,8 +8287,10 @@ int wolfTPM2_NVOpen(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, word32 nvIndex, XMEMCPY(newAuth.buffer, auth, authSz); } - /* Read the NV Index publicArea to have up to date NV Index Name */ - rc = wolfTPM2_NVReadPublic(dev, nv->handle.hndl, &nvPublic); + /* Read the NV Index publicArea to have up to date NV Index Name. + * Name is needed in case of parameter encryption */ + rc = wolfTPM2_NVComputeName(dev, nvIndex, &nv->handle.name, + &nv->attributes); if (rc != TPM_RC_SUCCESS) { #ifdef DEBUG_WOLFTPM printf("Failed to open (read) NV\n"); @@ -8226,21 +8298,11 @@ int wolfTPM2_NVOpen(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, word32 nvIndex, goto nv_open_exit; } - /* Compute NV Index name in case of parameter encryption */ -#ifndef WOLFTPM2_NO_WOLFCRYPT - rc = TPM2_HashNvPublic(&nvPublic, (byte*)&nv->handle.name.name, - &nv->handle.name.size); - if (rc != TPM_RC_SUCCESS) { - goto nv_open_exit; - } -#endif - if (auth != NULL && authSz > 0) { wolfTPM2_CopyAuth(&nv->handle.auth, &newAuth); } /* flag that the NV was "opened" and name was loaded */ nv->handle.nameLoaded = 1; - nv->attributes = nvPublic.attributes; nv_open_exit: TPM2_ForceZero(&newAuth, sizeof(newAuth)); diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 31ac6fba6..b0a50cc3d 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -2856,6 +2856,226 @@ static void test_wolfTPM2_NVWriteChunked(void) #endif } +/* OWNERWRITE/OWNERREAD index authorized by the owner hierarchy through the + * existing NV wrappers, multi-chunk under an HMAC parameter encryption + * session so the NV index name refresh is exercised. */ +static void test_wolfTPM2_NVOwnerAuth(void) +{ +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(WOLFTPM_WINAPI) + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_SESSION session; + WOLFTPM2_SESSION policySession; + WOLFTPM2_NV nv; + WOLFTPM2_HANDLE owner; + WOLFTPM2_HANDLE platform; + const word32 nvIndex = TPM2_DEMO_NVRAM_AUTH_INDEX; + const word32 ppIndex = 0x01400206; + word32 nvAttributes = (TPMA_NV_AUTHREAD | TPMA_NV_OWNERREAD | + TPMA_NV_OWNERWRITE | TPMA_NV_NO_DA | TPM_NT_ORDINARY); + byte buf[MAX_NV_BUFFER_SIZE*2 + 64]; + byte readBuf[sizeof(buf)]; + word32 readSz; + word32 i; + byte pcrIndex = 0; + byte policyDigest[TPM_MAX_DIGEST_SIZE]; + word32 policyDigestSz; + byte ownerName[4]; + PolicySecret_In secIn; + PolicySecret_Out secOut; + + XMEMSET(&dev, 0, sizeof(dev)); + XMEMSET(&session, 0, sizeof(session)); + XMEMSET(&policySession, 0, sizeof(policySession)); + XMEMSET(&nv, 0, sizeof(nv)); + XMEMSET(&owner, 0, sizeof(owner)); + XMEMSET(&platform, 0, sizeof(platform)); + for (i = 0; i < (word32)sizeof(buf); i++) { + buf[i] = (byte)(i & 0xFF); + } + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (rc != 0) { + printf("Test TPM Wrapper:\tNV owner auth:\t\tSkipped\n"); + return; + } + + owner.hndl = TPM_RH_OWNER; + rc = wolfTPM2_NVCreateAuth(&dev, &owner, &nv, nvIndex, nvAttributes, + (word32)sizeof(buf), NULL, 0); + if (rc == TPM_RC_NV_DEFINED) { + wolfTPM2_NVDeleteAuth(&dev, &owner, nvIndex); + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVCreateAuth(&dev, &owner, &nv, nvIndex, nvAttributes, + (word32)sizeof(buf), NULL, 0); + } + if (rc != 0) { + /* NV limits vary by device. */ + wolfTPM2_Cleanup(&dev); + printf("Test TPM Wrapper:\tNV owner auth:\t\tSkipped\n"); + return; + } + + /* No AUTHWRITE, so the NV index itself cannot authorize a write */ + rc = wolfTPM2_NVWriteAuth(&dev, &nv, nvIndex, buf, 16, 0); + AssertIntNE(rc, TPM_RC_SUCCESS); + + rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL, TPM_SE_HMAC, + TPM_ALG_CFB); + AssertIntEQ(rc, TPM_RC_SUCCESS); + rc = wolfTPM2_SetAuthSession(&dev, 1, &session, + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | + TPMA_SESSION_continueSession)); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + /* First chunk sets TPMA_NV_WRITTEN, the name must be refreshed */ + nv.handle.hndl = TPM_RH_OWNER; + rc = wolfTPM2_NVWriteAuth(&dev, &nv, nvIndex, buf, (word32)sizeof(buf), 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(nv.handle.hndl, TPM_RH_OWNER); + + /* OWNERREAD */ + readSz = (word32)sizeof(readBuf); + rc = wolfTPM2_NVReadAuth(&dev, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ((int)readSz, (int)sizeof(buf)); + AssertIntEQ(XMEMCMP(readBuf, buf, sizeof(buf)), 0); + + /* AUTHREAD with the empty NV index auth */ + XMEMSET(&nv, 0, sizeof(nv)); + XMEMSET(readBuf, 0, sizeof(readBuf)); + readSz = (word32)sizeof(readBuf); + rc = wolfTPM2_NVOpen(&dev, &nv, nvIndex, NULL, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + rc = wolfTPM2_NVReadAuth(&dev, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(XMEMCMP(readBuf, buf, sizeof(buf)), 0); + + wolfTPM2_SetAuthSession(&dev, 1, NULL, 0); + wolfTPM2_UnloadHandle(&dev, &session.handle); + + /* A caller satisfied policy (no PCR's) only covers one chunk */ + rc = wolfTPM2_StartSession(&dev, &policySession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + AssertIntEQ(rc, TPM_RC_SUCCESS); + rc = wolfTPM2_NVWriteAuthPolicy(&dev, &policySession, TPM_ALG_NULL, NULL, + 0, &nv, nvIndex, buf, MAX_NV_BUFFER_SIZE + 1, 0); + AssertIntEQ(rc, BUFFER_E); + readSz = MAX_NV_BUFFER_SIZE + 1; + rc = wolfTPM2_NVReadAuthPolicy(&dev, &policySession, TPM_ALG_NULL, NULL, + 0, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, BUFFER_E); + /* PCR array and size must be both set or both empty */ + rc = wolfTPM2_NVWriteAuthPolicy(&dev, &policySession, TPM_ALG_SHA256, + NULL, 1, &nv, nvIndex, buf, 16, 0); + AssertIntEQ(rc, BAD_FUNC_ARG); + rc = wolfTPM2_NVWriteAuthPolicy(&dev, &policySession, TPM_ALG_SHA256, + &pcrIndex, 0, &nv, nvIndex, buf, 16, 0); + AssertIntEQ(rc, BAD_FUNC_ARG); + readSz = 16; + rc = wolfTPM2_NVReadAuthPolicy(&dev, &policySession, TPM_ALG_SHA256, + NULL, 1, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, BAD_FUNC_ARG); + rc = wolfTPM2_NVReadAuthPolicy(&dev, &policySession, TPM_ALG_SHA256, + &pcrIndex, 0, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, BAD_FUNC_ARG); + wolfTPM2_UnloadHandle(&dev, &policySession.handle); + + wolfTPM2_SetAuthPassword(&dev, 0, NULL); + rc = wolfTPM2_NVDeleteAuth(&dev, &owner, nvIndex); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + /* POLICYREAD: PolicyCommandCode(NV_Read) + PolicySecret(owner) */ + ownerName[0] = (byte)((TPM_RH_OWNER >> 24) & 0xFF); + ownerName[1] = (byte)((TPM_RH_OWNER >> 16) & 0xFF); + ownerName[2] = (byte)((TPM_RH_OWNER >> 8) & 0xFF); + ownerName[3] = (byte)(TPM_RH_OWNER & 0xFF); + policyDigestSz = (word32)sizeof(policyDigest); + rc = wolfTPM2_PolicyCommandCodeMake(WOLFTPM2_WRAP_DIGEST, policyDigest, + &policyDigestSz, TPM_CC_NV_Read); + AssertIntEQ(rc, 0); + rc = wolfTPM2_PolicyHash(WOLFTPM2_WRAP_DIGEST, policyDigest, + &policyDigestSz, TPM_CC_PolicySecret, ownerName, sizeof(ownerName)); + AssertIntEQ(rc, 0); + rc = wolfTPM2_PolicyRefMake(WOLFTPM2_WRAP_DIGEST, policyDigest, + &policyDigestSz, NULL, 0); + AssertIntEQ(rc, 0); + + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVCreateAuthPolicy(&dev, &owner, &nv, nvIndex, + (TPMA_NV_POLICYREAD | TPMA_NV_OWNERWRITE | TPMA_NV_NO_DA | + TPM_NT_ORDINARY), 64, NULL, 0, policyDigest, (int)policyDigestSz); + AssertIntEQ(rc, TPM_RC_SUCCESS); + nv.handle.hndl = TPM_RH_OWNER; + rc = wolfTPM2_NVWriteAuth(&dev, &nv, nvIndex, buf, 32, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + rc = wolfTPM2_StartSession(&dev, &policySession, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL); + AssertIntEQ(rc, TPM_RC_SUCCESS); + rc = wolfTPM2_PolicyCommandCode(&dev, &policySession, TPM_CC_NV_Read); + AssertIntEQ(rc, TPM_RC_SUCCESS); + wolfTPM2_SetAuthHandle(&dev, 0, &owner); + XMEMSET(&secIn, 0, sizeof(secIn)); + secIn.authHandle = TPM_RH_OWNER; + secIn.policySession = policySession.handle.hndl; + rc = TPM2_PolicySecret(&secIn, &secOut); + AssertIntEQ(rc, TPM_RC_SUCCESS); + rc = wolfTPM2_SetAuthSession(&dev, 0, &policySession, + TPMA_SESSION_continueSession); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + XMEMSET(&nv, 0, sizeof(nv)); + XMEMSET(readBuf, 0, sizeof(readBuf)); + readSz = 32; + rc = wolfTPM2_NVReadAuthPolicy(&dev, &policySession, TPM_ALG_NULL, NULL, + 0, &nv, nvIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ((int)readSz, 32); + AssertIntEQ(XMEMCMP(readBuf, buf, 32), 0); + wolfTPM2_UnloadHandle(&dev, &policySession.handle); + + wolfTPM2_SetAuthPassword(&dev, 0, NULL); + rc = wolfTPM2_NVDeleteAuth(&dev, &owner, nvIndex); + AssertIntEQ(rc, TPM_RC_SUCCESS); + + /* PPWRITE/PPREAD, best effort: platform auth is usually unavailable + * after boot on a hardware TPM */ + platform.hndl = TPM_RH_PLATFORM; + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVCreateAuth(&dev, &platform, &nv, ppIndex, + (TPMA_NV_PPREAD | TPMA_NV_PPWRITE | TPMA_NV_PLATFORMCREATE | + TPMA_NV_NO_DA | TPM_NT_ORDINARY), 64, NULL, 0); + if (rc == TPM_RC_NV_DEFINED) { + wolfTPM2_NVDeleteAuth(&dev, &platform, ppIndex); + XMEMSET(&nv, 0, sizeof(nv)); + rc = wolfTPM2_NVCreateAuth(&dev, &platform, &nv, ppIndex, + (TPMA_NV_PPREAD | TPMA_NV_PPWRITE | TPMA_NV_PLATFORMCREATE | + TPMA_NV_NO_DA | TPM_NT_ORDINARY), 64, NULL, 0); + } + if (rc == TPM_RC_SUCCESS) { + rc = wolfTPM2_NVWriteAuth(&dev, &nv, ppIndex, buf, 32, 0); + AssertIntNE(rc, TPM_RC_SUCCESS); + + nv.handle.hndl = TPM_RH_PLATFORM; + rc = wolfTPM2_NVWriteAuth(&dev, &nv, ppIndex, buf, 32, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + XMEMSET(readBuf, 0, sizeof(readBuf)); + readSz = 32; + rc = wolfTPM2_NVReadAuth(&dev, &nv, ppIndex, readBuf, &readSz, 0); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(XMEMCMP(readBuf, buf, 32), 0); + + rc = wolfTPM2_NVDeleteAuth(&dev, &platform, ppIndex); + AssertIntEQ(rc, TPM_RC_SUCCESS); + } + wolfTPM2_Cleanup(&dev); + printf("Test TPM Wrapper:\tNV owner auth:\t\tPassed\n"); +#else + printf("Test TPM Wrapper:\tNV owner auth:\t\tSkipped\n"); +#endif +} + #ifndef WOLFTPM2_NO_WOLFCRYPT static void test_TPM2_command_process_buffer_cleanup(void) { @@ -11641,6 +11861,7 @@ int unit_tests(int argc, char *argv[]) test_wolfTPM2_BoundOwnEntity_ParamEnc(); test_wolfTPM2_SplitParamEncSession(); test_wolfTPM2_NVWriteChunked(); + test_wolfTPM2_NVOwnerAuth(); #ifndef WOLFTPM2_NO_WOLFCRYPT test_TPM2_command_process_buffer_cleanup(); #endif diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index c6bfdcc47..9d66ff15d 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -3274,6 +3274,7 @@ WOLFTPM_API int wolfTPM2_NVCreateAuthPolicy_ex(WOLFTPM2_DEV* dev, \ingroup wolfTPM2_Wrappers \brief Stores user data to a NV Index, at a given offset \note User data size should be less or equal to the NV Index maxSize specified using wolfTPM2_CreateAuth + \note For an index with TPMA_NV_OWNERWRITE or TPMA_NV_PPWRITE set nv->handle.hndl to TPM_RH_OWNER or TPM_RH_PLATFORM and nv->handle.auth to that hierarchy auth (after wolfTPM2_NVOpen) \return TPM_RC_SUCCESS: successful \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) @@ -3298,10 +3299,13 @@ WOLFTPM_API int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, \ingroup wolfTPM2_Wrappers \brief Stores user data to a NV Index, at a given offset. Allows using a policy session and PCR's for authentication. \note User data size should be less or equal to the NV Index maxSize specified using wolfTPM2_CreateAuth + \note For an index with TPMA_NV_OWNERWRITE or TPMA_NV_PPWRITE set nv->handle.hndl to TPM_RH_OWNER or TPM_RH_PLATFORM and nv->handle.auth to that hierarchy auth (after wolfTPM2_NVOpen) + \note pcrArray may be NULL with pcrArraySz 0 when the policy session was already satisfied by the caller (e.g. PolicySecret or PolicyCommandCode). The data must then fit in one MAX_NV_BUFFER_SIZE chunk, otherwise BUFFER_E is returned \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 + \return BUFFER_E: data too large for a policy without PCR's \param dev pointer to a TPM2_DEV struct \param tpmSession pointer to a WOLFTPM2_SESSION struct used with wolfTPM2_StartSession and wolfTPM2_SetAuthSession @@ -3327,6 +3331,7 @@ WOLFTPM_API int wolfTPM2_NVWriteAuthPolicy(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* \ingroup wolfTPM2_Wrappers \brief Extend data to an NV index \note When NV index is read it will return the digest + \note For an index with TPMA_NV_OWNERWRITE or TPMA_NV_PPWRITE set nv->handle.hndl to TPM_RH_OWNER or TPM_RH_PLATFORM and nv->handle.auth to that hierarchy auth (after wolfTPM2_NVOpen) \return TPM_RC_SUCCESS: successful \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) @@ -3350,6 +3355,7 @@ WOLFTPM_API int wolfTPM2_NVExtend(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, \ingroup wolfTPM2_Wrappers \brief Reads user data from a NV Index, starting at the given offset \note User data size should be less or equal to the NV Index maxSize specified using wolfTPM2_CreateAuth + \note For an index with TPMA_NV_OWNERREAD or TPMA_NV_PPREAD set nv->handle.hndl to TPM_RH_OWNER or TPM_RH_PLATFORM and nv->handle.auth to that hierarchy auth (after wolfTPM2_NVOpen) \return TPM_RC_SUCCESS: successful \return TPM_RC_FAILURE: generic failure (check TPM IO and TPM return code) @@ -3374,10 +3380,13 @@ WOLFTPM_API int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, \ingroup wolfTPM2_Wrappers \brief Reads user data from a NV Index, starting at the given offset. Allows using a policy session and PCR's for authentication. \note User data size should be less or equal to the NV Index maxSize specified using wolfTPM2_CreateAuth + \note For an index with TPMA_NV_OWNERREAD or TPMA_NV_PPREAD set nv->handle.hndl to TPM_RH_OWNER or TPM_RH_PLATFORM and nv->handle.auth to that hierarchy auth (after wolfTPM2_NVOpen) + \note pcrArray may be NULL with pcrArraySz 0 when the policy session was already satisfied by the caller (e.g. PolicySecret or PolicyCommandCode). The data must then fit in one MAX_NV_BUFFER_SIZE chunk, otherwise BUFFER_E is returned \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 + \return BUFFER_E: data too large for a policy without PCR's \param dev pointer to a TPM2_DEV struct \param tpmSession pointer to a WOLFTPM2_SESSION struct used with wolfTPM2_StartSession and wolfTPM2_SetAuthSession