summaryrefslogtreecommitdiffstats
path: root/src/tpm2/NVMarshal.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tpm2/NVMarshal.c4916
1 files changed, 4916 insertions, 0 deletions
diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c
new file mode 100644
index 0000000..c7cd1e0
--- /dev/null
+++ b/src/tpm2/NVMarshal.c
@@ -0,0 +1,4916 @@
+/********************************************************************************/
+/* */
+/* Marshalling and unmarshalling of state */
+/* Written by Stefan Berger */
+/* IBM Thomas J. Watson Research Center */
+/* */
+/* (c) Copyright IBM Corporation 2017,2018. */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions are */
+/* met: */
+/* */
+/* Redistributions of source code must retain the above copyright notice, */
+/* this list of conditions and the following disclaimer. */
+/* */
+/* Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in the */
+/* documentation and/or other materials provided with the distribution. */
+/* */
+/* Neither the names of the IBM Corporation nor the names of its */
+/* contributors may be used to endorse or promote products derived from */
+/* this software without specific prior written permission. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
+/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
+/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
+/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
+/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
+/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
+/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
+/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
+/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+/********************************************************************************/
+
+#include <string.h>
+#include <inttypes.h>
+
+#include "assert.h"
+
+#define _CRYPT_HASH_C_
+#define SESSION_PROCESS_C
+#define NV_C
+#define OBJECT_C
+#define PCR_C
+#define SESSION_C
+#include "Platform.h"
+#include "NVMarshal.h"
+#include "Marshal_fp.h"
+#include "Unmarshal_fp.h"
+#include "Global.h"
+#include "TpmTcpProtocol.h"
+#include "Simulator_fp.h"
+
+#define TPM_HAVE_TPM2_DECLARATIONS
+#include "tpm_library_intern.h"
+
+/*
+ * The TPM2 maintains a pcrAllocated shadow variable; the current active one is
+ * in gp.pcrAllocated and the one to be active after reboot is in NVRAM. So,
+ * this means we have to restore two of these variables when we resume. The
+ * tricky part is that the global gp will be restored by reading from NVRAM.
+ * Once that has been done the gp.pcrAllocated needs to be restored with the
+ * one that is supposed to be active. All of this is only supposed to happen
+ * when we resume a VM's volatile state.
+ */
+static struct shadow {
+ TPML_PCR_SELECTION pcrAllocated;
+ BOOL pcrAllocatedIsNew;
+} shadow;
+
+/* prevent misconfiguration: */
+typedef char assertion_failed_nvram[
+ (NV_USER_DYNAMIC_END < NV_USER_DYNAMIC) ? -1 : 0];
+
+typedef struct
+{
+ UINT16 version;
+ UINT32 magic;
+ UINT16 min_version; /* min. implementation version to accept the blob */
+} NV_HEADER;
+
+static UINT8 BOOL_Marshal(BOOL *boolean, BYTE **buffer, INT32 *size);
+static TPM_RC BOOL_Unmarshal(BOOL *boolean, BYTE **buffer, INT32 *size);
+
+/*
+ * There are compile-time optional variables that we marshal. To allow
+ * for some flexibility, we marshal them in such a way that these
+ * variables can be skipped if they are in the byte stream but are not
+ * needed by the implementation. The following block_skip data structure
+ * and related functions address this issue.
+ */
+typedef struct {
+ size_t idx;
+ size_t sz;
+ struct position {
+ BYTE *buffer;
+ INT32 size;
+ } pos[5]; /* more only needed for nested compile-time #ifdef's */
+} block_skip;
+
+/*
+ * This function is to be called when an optional block follows. It inserts
+ * a BOOL into the byte stream indicating whether the block is there or not.
+ * Then it leaves a 16bit zero in the byt stream and remembers the location
+ * of that zero. We will update the location with the number of optional
+ * bytes written when block_skip_write_pop() is called.
+ */
+static UINT16
+block_skip_write_push(block_skip *bs, BOOL has_block,
+ BYTE **buffer, INT32 *size) {
+ UINT16 written , w;
+ UINT16 zero = 0;
+ written = BOOL_Marshal(&has_block, buffer, size);
+ bs->pos[bs->idx].buffer = *buffer;
+ bs->pos[bs->idx].size = *size;
+ w = UINT16_Marshal(&zero, buffer, size);
+ if (w) {
+ bs->idx++;
+ pAssert(bs->idx < bs->sz);
+ written += w;
+ }
+ return written;
+}
+
+/*
+ * This function must be called for every block_skip_write_push() call.
+ * It has to be called once a compile-time optional block has been
+ * processed. It must be called after the #endif.
+ * In this function we updated the previously remembered location with
+ * the numbers of bytes to skip in case a block is there but it is not
+ * needed.
+ */
+static void
+block_skip_write_pop(block_skip *bs, INT32 *size) {
+ UINT16 skip;
+ unsigned i = --bs->idx;
+ pAssert((int)bs->idx >= 0);
+ skip = bs->pos[i].size - *size - sizeof(UINT16);
+ UINT16_Marshal(&skip, &bs->pos[i].buffer, &bs->pos[i].size);
+}
+
+/*
+ * This function must be called when unmarshalling a byte stream and
+ * a compile-time optional block follows. In case the compile-time
+ * optional block is there but not in the byte stream, we log an error.
+ * In case the bytes stream contains the block, but we don't need it
+ * we skip it. In the other cases we don't need to do anything since
+ * the code is 'in sync' with the byte stream.
+ */
+static TPM_RC
+block_skip_read(BOOL needs_block, BYTE **buffer, INT32 *size,
+ const char *name, const char *field,
+ BOOL *skip_code)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ BOOL has_block;
+ UINT16 blocksize;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&has_block, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&blocksize, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (!has_block && needs_block) {
+ TPMLIB_LogTPM2Error("%s needs missing %s\n", name, field);
+ rc = TPM_RC_BAD_PARAMETER;
+ } else if (has_block && !needs_block) {
+ /* byte stream has the data but we don't need them */
+ *buffer += blocksize;
+ *size -= blocksize;
+ *skip_code = TRUE;
+ }
+ }
+ return rc;
+}
+
+#define BLOCK_SKIP_INIT \
+ block_skip block_skip = { \
+ .idx = 0, \
+ .sz = ARRAY_SIZE(block_skip.pos), \
+ }
+
+#define BLOCK_SKIP_WRITE_PUSH(HAS_BLOCK, BUFFER, POS) \
+ block_skip_write_push(&block_skip, HAS_BLOCK, BUFFER, POS)
+
+#define BLOCK_SKIP_WRITE_POP(SIZE) \
+ block_skip_write_pop(&block_skip, SIZE)
+
+#define BLOCK_SKIP_WRITE_CHECK \
+ pAssert(block_skip.idx == 0)
+
+#define BLOCK_SKIP_READ(SKIP_MARK, NEEDS_BLOCK, BUFFER, SIZE, NAME, FIELD) \
+ { \
+ BOOL skip_code = FALSE; \
+ rc = block_skip_read(NEEDS_BLOCK, buffer, size, \
+ NAME, FIELD, &skip_code); \
+ if (rc == TPM_RC_SUCCESS && skip_code) \
+ goto SKIP_MARK; \
+ }
+
+static unsigned int _ffsll(long long bits)
+{
+ size_t i = 0;
+
+ for (i = 0; i < 8 * sizeof(bits); i++) {
+ if (bits & (1ULL << i))
+ return i + 1;
+ }
+ return 0;
+}
+
+/* BOOL is 'int' but we store a single byte */
+static UINT8
+BOOL_Marshal(BOOL *boolean, BYTE **buffer, INT32 *size)
+{
+ UINT8 _bool = (*boolean != 0);
+ UINT16 written = 0;
+ written += UINT8_Marshal(&_bool, buffer, size);
+ return written;
+}
+
+static TPM_RC
+BOOL_Unmarshal(BOOL *boolean, BYTE **buffer, INT32 *size)
+{
+ UINT8 _bool;
+ TPM_RC rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT8_Unmarshal(&_bool, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ *boolean = (_bool != 0);
+ }
+
+ return rc;
+}
+
+static UINT16
+SEED_COMPAT_LEVEL_Marshal(SEED_COMPAT_LEVEL *source,
+ BYTE **buffer, INT32 *size)
+{
+ return UINT8_Marshal((UINT8 *)source, buffer, size);
+}
+
+static TPM_RC
+SEED_COMPAT_LEVEL_Unmarshal(SEED_COMPAT_LEVEL *source,
+ BYTE **buffer, INT32 *size,
+ const char *name)
+{
+ TPM_RC rc;
+
+ rc = UINT8_Unmarshal((UINT8 *)source, buffer, size);
+ if (rc == TPM_RC_SUCCESS && *source > SEED_COMPAT_LEVEL_LAST) {
+ TPMLIB_LogTPM2Error("%s compatLevel '%u' higher than supported '%u'\n",
+ name, *source, SEED_COMPAT_LEVEL_LAST);
+ rc = TPM_RC_BAD_VERSION;
+ }
+ return rc;
+}
+
+static int
+TPM2B_Cmp(const TPM2B *t1, const TPM2B *t2)
+{
+ if (t1->size != t2->size)
+ return 1;
+
+ return memcmp(t1->buffer, t2->buffer, t1->size);
+}
+
+static UINT16
+TPM2B_PROOF_Marshal(TPM2B_PROOF *source, BYTE **buffer, INT32 *size)
+{
+ UINT16 written = 0;
+ written += TPM2B_Marshal(&source->b, sizeof(source->t.buffer), buffer, size);
+ return written;
+}
+
+static TPM_RC
+TPM2B_PROOF_Unmarshal(TPM2B_PROOF *target, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&target->b, sizeof(target->t.buffer), buffer, size);
+ }
+ return rc;
+}
+
+static TPM_RC
+UINT32_Unmarshal_Check(UINT32 *data, UINT32 exp, BYTE **buffer, INT32 *size,
+ const char *msg)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(data, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && exp != *data) {
+ TPMLIB_LogTPM2Error("%s: Expected value: 0x%08x, found: 0x%08x\n",
+ __func__, exp, *data);
+ rc = TPM_RC_BAD_TAG;
+ }
+ return rc;
+}
+
+static void
+NV_HEADER_INIT(NV_HEADER *t, UINT16 version, UINT32 magic, UINT16 min_version)
+{
+ t->version = version;
+ t->magic = magic;
+ t->min_version = min_version;
+}
+
+static UINT16
+NV_HEADER_Marshal(BYTE **buffer, INT32 *size, UINT16 version, UINT32 magic,
+ UINT16 min_version)
+{
+ UINT16 written;
+ NV_HEADER hdr;
+
+ NV_HEADER_INIT(&hdr, version, magic, min_version);
+
+ written = UINT16_Marshal(&hdr.version, buffer, size);
+ written += UINT32_Marshal(&hdr.magic, buffer, size);
+ if (version >= 2)
+ written += UINT16_Marshal(&hdr.min_version, buffer, size);
+
+ return written;
+}
+
+static TPM_RC
+NV_HEADER_UnmarshalVerbose(NV_HEADER *data, BYTE **buffer, INT32 *size,
+ UINT16 cur_version, UINT32 exp_magic, BOOL verbose)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&data->version, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->magic, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && exp_magic != data->magic) {
+ if (verbose)
+ TPMLIB_LogTPM2Error("%s: Invalid magic. Expected 0x%08x, got 0x%08x\n",
+ __func__, exp_magic, data->magic);
+ rc = TPM_RC_BAD_TAG;
+ }
+
+ data->min_version = 0;
+ if (rc == TPM_RC_SUCCESS && data->version >= 2) {
+
+ rc = UINT16_Unmarshal(&data->min_version, buffer, size);
+
+ if (rc == TPM_RC_SUCCESS && data->min_version > cur_version) {
+ if (verbose)
+ TPMLIB_LogTPM2Error("%s: Minimum version %u higher than "
+ "implementation version %u for type 0x%08x\n",
+ __func__, data->min_version, cur_version,
+ exp_magic);
+ rc = TPM_RC_BAD_VERSION;
+ }
+ }
+
+ return rc;
+}
+
+static TPM_RC
+NV_HEADER_Unmarshal(NV_HEADER *data, BYTE **buffer, INT32 *size,
+ UINT16 cur_version, UINT32 exp_magic)
+{
+ return NV_HEADER_UnmarshalVerbose(data, buffer, size, cur_version,
+ exp_magic, true);
+}
+
+#define NV_INDEX_MAGIC 0x2547265a
+#define NV_INDEX_VERSION 2
+static UINT16
+NV_INDEX_Marshal(NV_INDEX *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ NV_INDEX_VERSION,
+ NV_INDEX_MAGIC, 1);
+
+ written += TPMS_NV_PUBLIC_Marshal(&data->publicArea, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->authValue, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+NV_INDEX_Unmarshal(NV_INDEX *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ NV_INDEX_VERSION, NV_INDEX_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMS_NV_PUBLIC_Unmarshal(&data->publicArea, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->authValue, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "NV_INDEX", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+ return rc;
+}
+
+#define DRBG_STATE_MAGIC 0x6fe83ea1
+#define DRBG_STATE_VERSION 2
+static UINT16
+DRBG_STATE_Marshal(DRBG_STATE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ size_t i;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ DRBG_STATE_VERSION, DRBG_STATE_MAGIC, 1);
+ written += UINT64_Marshal(&data->reseedCounter, buffer, size);
+ written += UINT32_Marshal(&data->magic, buffer, size);
+
+ array_size = sizeof(data->seed.bytes);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal(&data->seed.bytes[0], array_size, buffer, size);
+
+ array_size = ARRAY_SIZE(data->lastValue);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++) {
+ written += UINT32_Marshal(&data->lastValue[i], buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+DRBG_STATE_Unmarshal(DRBG_STATE *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc= TPM_RC_SUCCESS;
+ size_t i;
+ NV_HEADER hdr;
+ UINT16 array_size = 0;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ DRBG_STATE_VERSION, DRBG_STATE_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->reseedCounter, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->magic, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (array_size != ARRAY_SIZE(data->seed.bytes)) {
+ TPMLIB_LogTPM2Error("Non-matching DRBG_STATE seed array size. "
+ "Expected %zu, got %u\n",
+ ARRAY_SIZE(data->seed.bytes), array_size);
+ rc = TPM_RC_SIZE;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal(&data->seed.bytes[0], array_size, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (array_size != ARRAY_SIZE(data->lastValue)) {
+ TPMLIB_LogTPM2Error("Non-matching DRBG_STATE lastValue array size. "
+ "Expected %zu, got %u\n",
+ ARRAY_SIZE(data->lastValue), array_size);
+ rc = TPM_RC_SIZE;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ for (i = 0; i < ARRAY_SIZE(data->lastValue) && rc == TPM_RC_SUCCESS; i++) {
+ rc = UINT32_Unmarshal(&data->lastValue[i], buffer, size);
+ }
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "DRBG_STATE", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+
+#define PCR_POLICY_MAGIC 0x176be626
+#define PCR_POLICY_VERSION 2
+static UINT16
+PCR_POLICY_Marshal(PCR_POLICY *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ unsigned i;
+ UINT16 array_size = ARRAY_SIZE(data->hashAlg);
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PCR_POLICY_VERSION,
+ PCR_POLICY_MAGIC, 1);
+
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ /* TPMI_ALG_HASH_Unmarshal errors on algid 0 */
+ written += TPM_ALG_ID_Marshal(&data->hashAlg[i], buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->policy[i], buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+PCR_POLICY_Unmarshal(PCR_POLICY *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc= TPM_RC_SUCCESS;
+ unsigned i;
+ UINT16 array_size;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PCR_POLICY_VERSION, PCR_POLICY_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ if (array_size != ARRAY_SIZE(data->hashAlg)) {
+ TPMLIB_LogTPM2Error("Non-matching PCR_POLICY array size. "
+ "Expected %zu, got %u\n",
+ ARRAY_SIZE(data->hashAlg), array_size);
+ rc = TPM_RC_SIZE;
+ }
+ }
+
+ for (i = 0;
+ rc == TPM_RC_SUCCESS &&
+ i < ARRAY_SIZE(data->hashAlg);
+ i++) {
+ /* TPMI_ALG_HASH_Unmarshal errors on algid 0 */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->hashAlg[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->policy[i], buffer, size);
+ }
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PCR_POLICY", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+ return rc;
+}
+
+#define ORDERLY_DATA_MAGIC 0x56657887
+#define ORDERLY_DATA_VERSION 2
+
+static UINT16
+ORDERLY_DATA_Marshal(ORDERLY_DATA *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BOOL has_block;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ ORDERLY_DATA_VERSION, ORDERLY_DATA_MAGIC, 1);
+ written += UINT64_Marshal(&data->clock, buffer, size);
+ written += UINT8_Marshal(&data->clockSafe, buffer, size);
+
+ written += DRBG_STATE_Marshal(&data->drbgState, buffer, size);
+
+#if ACCUMULATE_SELF_HEAL_TIMER
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if ACCUMULATE_SELF_HEAL_TIMER
+ written += UINT64_Marshal(&data->selfHealTimer, buffer, size);
+ written += UINT64_Marshal(&data->lockoutTimer, buffer, size);
+ written += UINT64_Marshal(&data->time, buffer, size);
+#endif // ACCUMULATE_SELF_HEAL_TIMER
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+ORDERLY_DATA_Unmarshal(ORDERLY_DATA *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ BOOL needs_block;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ ORDERLY_DATA_VERSION, ORDERLY_DATA_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->clock, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT8_Unmarshal(&data->clockSafe, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = DRBG_STATE_Unmarshal(&data->drbgState, buffer, size);
+ }
+
+#if ACCUMULATE_SELF_HEAL_TIMER
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_self_heal_timer, needs_block, buffer, size,
+ "ORDERLY_DATA", "selfHealTimer");
+ }
+#if ACCUMULATE_SELF_HEAL_TIMER
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->selfHealTimer, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->lockoutTimer, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->time, buffer, size);
+ }
+#endif // ACCUMULATE_SELF_HEAL_TIMER
+skip_self_heal_timer:
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "ORDERLY_DATA", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+
+#define PCR_SAVE_MAGIC 0x7372eabc
+#define PCR_SAVE_VERSION 2
+static UINT16
+PCR_SAVE_Marshal(PCR_SAVE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written = 0;
+ TPM_ALG_ID algid;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PCR_SAVE_VERSION, PCR_SAVE_MAGIC, 1);
+
+ array_size = NUM_STATIC_PCR;
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+#if ALG_SHA1
+ algid = TPM_ALG_SHA1;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha1);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha1, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA256
+ algid = TPM_ALG_SHA256;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha256);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha256, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA384
+ algid = TPM_ALG_SHA384;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha384);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha384, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA512
+ algid = TPM_ALG_SHA512;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha512);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha512, array_size,
+ buffer, size);
+#endif
+#if ALG_SM3_256
+ algid = TPM_ALG_SM3_256;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sm3_256);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sm3_256, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA3_256 || ALG_SHA3_384 || ALG_SHA3_512 || ALG_SM3_256
+#error SHA3 and SM3 are not supported
+#endif
+
+ /* end marker */
+ algid = TPM_ALG_NULL;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+/*
+ * Get the PCR banks that are active so that we know what PCRs need to be
+ * restored. Only data for active PCR banks needs to restored, inactive PCR
+ * banks need no data restored.
+ */
+static UINT64
+pcrbanks_algs_active(const TPML_PCR_SELECTION *pcrAllocated)
+{
+ UINT64 algs_active = 0;
+ unsigned i, j;
+
+ for(i = 0; i < pcrAllocated->count; i++) {
+ for (j = 0; j < pcrAllocated->pcrSelections[i].sizeofSelect; j++) {
+ if (pcrAllocated->pcrSelections[i].pcrSelect[j]) {
+ algs_active |= 1 << pcrAllocated->pcrSelections[i].hash;
+ break;
+ }
+ }
+ }
+
+ return algs_active;
+}
+
+static TPM_RC
+PCR_SAVE_Unmarshal(PCR_SAVE *data, BYTE **buffer, INT32 *size,
+ const TPML_PCR_SELECTION *pcrAllocated)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ UINT16 array_size, needed_size = 0;
+ NV_HEADER hdr;
+ TPM_ALG_ID algid;
+ BOOL end = FALSE;
+ BYTE *t = NULL;
+ UINT64 algs_needed = pcrbanks_algs_active(pcrAllocated);
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PCR_SAVE_VERSION, PCR_SAVE_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != NUM_STATIC_PCR) {
+ TPMLIB_LogTPM2Error("Non-matching PCR_SAVE NUM_STATIC_PCR. "
+ "Expected %zu, got %u\n",
+ sizeof(NUM_STATIC_PCR), array_size);
+ rc = TPM_RC_SIZE;
+ }
+
+ while (rc == TPM_RC_SUCCESS && !end) {
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&algid, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ switch (algid) {
+#if ALG_SHA1
+ case TPM_ALG_SHA1:
+ needed_size = sizeof(data->Sha1);
+ t = (BYTE *)&data->Sha1;
+ break;
+#endif
+#if ALG_SHA256
+ case TPM_ALG_SHA256:
+ needed_size = sizeof(data->Sha256);
+ t = (BYTE *)&data->Sha256;
+ break;
+#endif
+#if ALG_SHA384
+ case TPM_ALG_SHA384:
+ needed_size = sizeof(data->Sha384);
+ t = (BYTE *)&data->Sha384;
+ break;
+#endif
+#if ALG_SHA512
+ case TPM_ALG_SHA512:
+ needed_size = sizeof(data->Sha512);
+ t = (BYTE *)&data->Sha512;
+ break;
+#endif
+#if ALG_SM3_256
+ case TPM_ALG_SM3_256:
+ needed_size = sizeof(data->Sm3_256);
+ t = (BYTE *)&data->Sm3_256;
+ break;
+#endif
+#if ALG_SHA3_256 || ALG_SHA3_384 || ALG_SHA3_512 || ALG_SM3_256
+#error SHA3 and SM3 are not supported
+#endif
+ case TPM_ALG_NULL:
+ /* end marker */
+ end = TRUE;
+ t = NULL;
+ break;
+ default:
+ TPMLIB_LogTPM2Error("PCR_SAVE: Unsupported algid %d.",
+ algid);
+ rc = TPM_RC_BAD_PARAMETER;
+ t = NULL;
+ }
+ }
+ if (t) {
+ if (rc == TPM_RC_SUCCESS) {
+ algs_needed &= ~(1 << algid);
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && array_size != needed_size) {
+ TPMLIB_LogTPM2Error("PCR_SAVE: Bad size for PCRs for hash 0x%x; "
+ "Expected %u, got %d\n",
+ algid, needed_size, array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal(t, array_size, buffer, size);
+ }
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS && algs_needed) {
+ TPMLIB_LogTPM2Error("PCR_SAVE: Missing data for hash algorithm %d.\n",
+ _ffsll(algs_needed) - 1);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PCR_SAVE", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+
+
+#ifdef PCR_C
+
+#define PCR_MAGIC 0xe95f0387
+#define PCR_VERSION 2
+static UINT16
+PCR_Marshal(PCR *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ TPM_ALG_ID algid;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PCR_VERSION, PCR_MAGIC, 1);
+
+#if ALG_SHA1
+ algid = TPM_ALG_SHA1;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha1Pcr);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha1Pcr, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA256
+ algid = TPM_ALG_SHA256;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha256Pcr);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha256Pcr, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA384
+ algid = TPM_ALG_SHA384;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha384Pcr);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha384Pcr, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA512
+ algid = TPM_ALG_SHA512;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sha512Pcr);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sha512Pcr, array_size,
+ buffer, size);
+#endif
+#if ALG_SM3_256
+ algid = TPM_ALG_SM3_256;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ array_size = sizeof(data->Sm3_256Pcr);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->Sm3_256Pcr, array_size,
+ buffer, size);
+#endif
+#if ALG_SHA3_256 || ALG_SHA3_384 || ALG_SHA3_512 || ALG_SM3_256
+#error SHA3 and SM3 are not supported
+#endif
+
+ /* end marker */
+ algid = TPM_ALG_NULL;
+ written += TPM_ALG_ID_Marshal(&algid, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+PCR_Unmarshal(PCR *data, BYTE **buffer, INT32 *size,
+ const TPML_PCR_SELECTION *pcrAllocated)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ BOOL end = FALSE;
+ BYTE *t = NULL;
+ UINT16 needed_size = 0, array_size;
+ TPM_ALG_ID algid;
+ UINT64 algs_needed = pcrbanks_algs_active(pcrAllocated);
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PCR_VERSION, PCR_MAGIC);
+ }
+
+ while (rc == TPM_RC_SUCCESS && !end) {
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&algid, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ switch (algid) {
+#if ALG_SHA1
+ case TPM_ALG_SHA1:
+ needed_size = sizeof(data->Sha1Pcr);
+ t = (BYTE *)&data->Sha1Pcr;
+ break;
+#endif
+#if ALG_SHA256
+ case TPM_ALG_SHA256:
+ needed_size = sizeof(data->Sha256Pcr);
+ t = (BYTE *)&data->Sha256Pcr;
+ break;
+#endif
+#if ALG_SHA384
+ case TPM_ALG_SHA384:
+ needed_size = sizeof(data->Sha384Pcr);
+ t = (BYTE *)&data->Sha384Pcr;
+ break;
+#endif
+#if ALG_SHA512
+ case TPM_ALG_SHA512:
+ needed_size = sizeof(data->Sha512Pcr);
+ t = (BYTE *)&data->Sha512Pcr;
+ break;
+#endif
+#if ALG_SM3_256
+ case TPM_ALG_SM3_256:
+ needed_size = sizeof(data->Sm3_256Pcr);
+ t = (BYTE *)&data->Sm3_256Pcr;
+ break;
+#endif
+#if ALG_SHA3_256 || ALG_SHA3_384 || ALG_SHA3_512 || ALG_SM3_256
+#error SHA3 and SM3 are not supported
+#endif
+ case TPM_ALG_NULL:
+ /* end marker */
+ end = TRUE;
+ t = NULL;
+ break;
+ default:
+ TPMLIB_LogTPM2Error("PCR: Unsupported algid %d.",
+ algid);
+ rc = TPM_RC_BAD_PARAMETER;
+ t = NULL;
+ }
+ }
+ if (t) {
+ if (rc == TPM_RC_SUCCESS) {
+ algs_needed &= ~(1 << algid);
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && array_size != needed_size) {
+ TPMLIB_LogTPM2Error("PCR: Bad size for PCR for hash 0x%x; "
+ "Expected %u, got %d\n",
+ algid, needed_size, array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal(t, array_size, buffer, size);
+ }
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS && algs_needed) {
+ TPMLIB_LogTPM2Error("PCR: Missing data for hash algorithm %d.\n",
+ _ffsll(algs_needed) - 1);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PCR", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+#endif
+
+#define PCR_AUTHVALUE_MAGIC 0x6be82eaf
+#define PCR_AUTHVALUE_VERSION 2
+static UINT16
+PCR_AUTHVALUE_Marshal(PCR_AUTHVALUE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ size_t i;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PCR_AUTHVALUE_VERSION, PCR_AUTHVALUE_MAGIC, 1);
+
+ array_size = ARRAY_SIZE(data->auth);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++) {
+ written += TPM2B_DIGEST_Marshal(&data->auth[i], buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+PCR_AUTHVALUE_Unmarshal(PCR_AUTHVALUE *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ size_t i;
+ NV_HEADER hdr;
+ UINT16 array_size = 0;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PCR_AUTHVALUE_VERSION, PCR_AUTHVALUE_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(data->auth)) {
+ TPMLIB_LogTPM2Error("PCR_AUTHVALUE: Bad array size for auth; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(data->auth), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ for (i = 0; i < ARRAY_SIZE(data->auth) && rc == TPM_RC_SUCCESS; i++) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->auth[i], buffer, size);
+ }
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PCR_AUTHVALUE", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+
+#define STATE_CLEAR_DATA_MAGIC 0x98897667
+#define STATE_CLEAR_DATA_VERSION 2
+
+static UINT16
+STATE_CLEAR_DATA_Marshal(STATE_CLEAR_DATA *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ STATE_CLEAR_DATA_VERSION,
+ STATE_CLEAR_DATA_MAGIC, 1);
+ written += BOOL_Marshal(&data->shEnable, buffer, size);
+ written += BOOL_Marshal(&data->ehEnable, buffer, size);
+ written += BOOL_Marshal(&data->phEnableNV, buffer, size);
+ written += UINT16_Marshal(&data->platformAlg, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->platformPolicy, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->platformAuth, buffer, size);
+ written += PCR_SAVE_Marshal(&data->pcrSave, buffer, size);
+ written += PCR_AUTHVALUE_Marshal(&data->pcrAuthValues, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+STATE_CLEAR_DATA_Unmarshal(STATE_CLEAR_DATA *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ STATE_CLEAR_DATA_VERSION,
+ STATE_CLEAR_DATA_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->shEnable, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->ehEnable, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->phEnableNV, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&data->platformAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->platformPolicy, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->platformAuth, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = PCR_SAVE_Unmarshal(&data->pcrSave, buffer, size, &shadow.pcrAllocated);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = PCR_AUTHVALUE_Unmarshal(&data->pcrAuthValues, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "STATE_CLEAR_DATA", "version 3 or later");
+ /* future versions nest-append here */
+ }
+skip_future_versions:
+
+ return rc;
+}
+
+#define STATE_RESET_DATA_MAGIC 0x01102332
+#define STATE_RESET_DATA_VERSION 4
+
+static TPM_RC
+STATE_RESET_DATA_Unmarshal(STATE_RESET_DATA *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ BOOL needs_block;
+ UINT16 array_size;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ STATE_RESET_DATA_VERSION,
+ STATE_RESET_DATA_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_PROOF_Unmarshal(&data->nullProof, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&data->nullSeed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->clearCount, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->objectContextID, buffer, size);
+ }
+
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(data->contextArray)) {
+ TPMLIB_LogTPM2Error("STATE_RESET_DATA: Bad array size for contextArray; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(data->contextArray), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ size_t i;
+ if (hdr.version <= 3) {
+ /* version <= 3 was writing an array of UINT8 */
+ UINT8 element;
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ rc = UINT8_Unmarshal(&element, buffer, size);
+ data->contextArray[i] = element;
+ }
+ s_ContextSlotMask = 0xff;
+ } else {
+ /* version 4 and later an array of UINT16 */
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ rc = UINT16_Unmarshal(&data->contextArray[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&s_ContextSlotMask, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (s_ContextSlotMask != 0xffff && s_ContextSlotMask != 0x00ff) {
+ TPMLIB_LogTPM2Error("STATE_RESET_DATA: s_ContextSlotMask has bad value: 0x%04x\n",
+ s_ContextSlotMask);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ }
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->contextCounter, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->commandAuditDigest,
+ buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->restartCount, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->pcrCounter, buffer, size);
+ }
+
+#if ALG_ECC
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_alg_ecc, needs_block, buffer, size,
+ "STATE_RESET_DATA", "commitCounter");
+ }
+#if ALG_ECC
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->commitCounter, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->commitNonce, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != sizeof(data->commitArray)) {
+ TPMLIB_LogTPM2Error("STATE_RESET_DATA: Bad array size for commitArray; "
+ "expected %zu, got %u\n",
+ sizeof(data->commitArray), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal((BYTE *)&data->commitArray, array_size,
+ buffer, size);
+ }
+#endif
+skip_alg_ecc:
+
+ /* default values before conditional block */
+ data->nullSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 3, buffer, size,
+ "STATE_RESET_DATA", "version 3 or later");
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SEED_COMPAT_LEVEL_Unmarshal(&gr.nullSeedCompatLevel,
+ buffer, size, "nullSeed");
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "STATE_RESET_DATA", "version 4 or later");
+ }
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+static UINT16
+STATE_RESET_DATA_Marshal(STATE_RESET_DATA *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BOOL has_block;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+ size_t i;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ STATE_RESET_DATA_VERSION,
+ STATE_RESET_DATA_MAGIC, 4);
+ written += TPM2B_PROOF_Marshal(&data->nullProof, buffer, size);
+ written += TPM2B_Marshal(&data->nullSeed.b, sizeof(data->nullSeed.t.buffer), buffer, size);
+ written += UINT32_Marshal(&data->clearCount, buffer, size);
+ written += UINT64_Marshal(&data->objectContextID, buffer, size);
+
+ array_size = ARRAY_SIZE(data->contextArray);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++)
+ written += UINT16_Marshal(&data->contextArray[i], buffer, size);
+
+ if (s_ContextSlotMask != 0x00ff && s_ContextSlotMask != 0xffff) {
+ /* TPM wasn't initialized, so s_ContextSlotMask wasn't set */
+ s_ContextSlotMask = 0xffff;
+ }
+ written += UINT16_Marshal(&s_ContextSlotMask, buffer, size);
+
+ written += UINT64_Marshal(&data->contextCounter, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->commandAuditDigest,
+ buffer, size);
+ written += UINT32_Marshal(&data->restartCount, buffer, size);
+ written += UINT32_Marshal(&data->pcrCounter, buffer, size);
+#if ALG_ECC
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if ALG_ECC
+ written += UINT64_Marshal(&data->commitCounter, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->commitNonce, buffer, size);
+
+ array_size = sizeof(data->commitArray);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->commitArray, array_size,
+ buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ written += SEED_COMPAT_LEVEL_Marshal(&data->nullSeedCompatLevel,
+ buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+#define BN_PRIME_T_MAGIC 0x2fe736ab
+#define BN_PRIME_T_VERSION 2
+static UINT16
+bn_prime_t_Marshal(bn_prime_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written, numbytes;
+ size_t i, idx;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ BN_PRIME_T_VERSION, BN_PRIME_T_MAGIC, 1);
+
+ /* we do not write 'allocated' */
+ numbytes = data->size * sizeof(crypt_uword_t);
+ written += UINT16_Marshal(&numbytes, buffer, size);
+
+ for (i = 0, idx = 0;
+ i < numbytes;
+ i += sizeof(crypt_uword_t), idx += 1) {
+#if RADIX_BITS == 64
+ written += UINT64_Marshal(&data->d[idx], buffer, size);
+#elif RADIX_BITS == 32
+ written += UINT32_Marshal(&data->d[idx], buffer, size);
+#else
+#error RADIX_BYTES it no defined
+#endif
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+bn_prime_t_Unmarshal(bn_prime_t *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ size_t i, idx;
+ UINT16 numbytes = 0;
+ UINT32 word;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ BN_PRIME_T_VERSION,
+ BN_PRIME_T_MAGIC);
+ }
+
+ data->allocated = ARRAY_SIZE(data->d);
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&numbytes, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* coverity: num_bytes is sanitized here! */
+ data->size = (numbytes + sizeof(crypt_uword_t) - 1) / sizeof(crypt_word_t);
+ if (data->size > data->allocated) {
+ TPMLIB_LogTPM2Error("bn_prime_t: Require size larger %zu than "
+ "allocated %zu\n",
+ (size_t)data->size, (size_t)data->allocated);
+ rc = TPM_RC_SIZE;
+ data->size = 0;
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ for (i = 0, idx = 0;
+ i < numbytes && rc == TPM_RC_SUCCESS;
+ i += sizeof(UINT32), idx += 1) {
+ rc = UINT32_Unmarshal(&word, buffer, size);
+#if RADIX_BITS == 64
+ data->d[idx / 2] <<= 32;
+ data->d[idx / 2] |= word;
+#elif RADIX_BITS == 32
+ data->d[idx] = word;
+#endif
+ }
+ }
+
+#if RADIX_BITS == 64
+ if (rc == TPM_RC_SUCCESS) {
+ if (idx & 1)
+ data->d[idx / 2] <<= 32;
+ }
+#endif
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "BN_PRIME_T", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+#define PRIVATE_EXPONENT_T_MAGIC 0x854eab2
+#define PRIVATE_EXPONENT_T_VERSION 2
+static UINT16
+privateExponent_t_Marshal(privateExponent_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PRIVATE_EXPONENT_T_VERSION,
+ PRIVATE_EXPONENT_T_MAGIC, 1);
+#if CRT_FORMAT_RSA == NO
+#error Missing code
+#else
+ written += bn_prime_t_Marshal(&data->Q, buffer, size);
+ written += bn_prime_t_Marshal(&data->dP, buffer, size);
+ written += bn_prime_t_Marshal(&data->dQ, buffer, size);
+ written += bn_prime_t_Marshal(&data->qInv, buffer, size);
+#endif
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+privateExponent_t_Unmarshal(privateExponent_t *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PRIVATE_EXPONENT_T_VERSION,
+ PRIVATE_EXPONENT_T_MAGIC);
+ }
+
+#if CRT_FORMAT_RSA == NO
+#error Missing code
+#else
+ if (rc == TPM_RC_SUCCESS) {
+ rc = bn_prime_t_Unmarshal(&data->Q, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = bn_prime_t_Unmarshal(&data->dP, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = bn_prime_t_Unmarshal(&data->dQ, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = bn_prime_t_Unmarshal(&data->qInv, buffer, size);
+ }
+#endif
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PRIVATE_EXPONENT_T", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+static UINT16
+HASH_STATE_TYPE_Marshal(HASH_STATE_TYPE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+
+ written = UINT8_Marshal(data, buffer, size);
+
+ return written;
+}
+
+static UINT16
+HASH_STATE_TYPE_Unmarshal(HASH_STATE_TYPE *data, BYTE **buffer, INT32 *size)
+{
+ return UINT8_Unmarshal(data, buffer, size);
+}
+
+static inline UINT16
+SHA_LONG_Marshal(SHA_LONG *data, BYTE **buffer, INT32 *size)
+{
+ return UINT32_Marshal(data, buffer, size);
+}
+
+static inline UINT16
+SHA_LONG_Unmarshal(SHA_LONG *data, BYTE **buffer, INT32 *size)
+{
+ return UINT32_Unmarshal(data, buffer, size);
+}
+
+static inline UINT16
+SHA_LONG64_Marshal(SHA_LONG64 *data, BYTE **buffer, INT32 *size)
+{
+ assert(sizeof(*data) == 8);
+ return UINT64_Marshal((UINT64 *)data, buffer, size);
+}
+
+static inline UINT16
+SHA_LONG64_Unmarshal(SHA_LONG64 *data, BYTE **buffer, INT32 *size)
+{
+ assert(sizeof(*data) == 8);
+ return UINT64_Unmarshal((UINT64 *)data, buffer, size);
+}
+
+#if ALG_SHA1
+
+#define HASH_STATE_SHA1_MAGIC 0x19d46f50
+#define HASH_STATE_SHA1_VERSION 2
+
+static UINT16
+tpmHashStateSHA1_Marshal(tpmHashStateSHA1_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ HASH_STATE_SHA1_VERSION,
+ HASH_STATE_SHA1_MAGIC,1);
+ written += SHA_LONG_Marshal(&data->h0, buffer, size);
+ written += SHA_LONG_Marshal(&data->h1, buffer, size);
+ written += SHA_LONG_Marshal(&data->h2, buffer, size);
+ written += SHA_LONG_Marshal(&data->h3, buffer, size);
+ written += SHA_LONG_Marshal(&data->h4, buffer, size);
+ written += SHA_LONG_Marshal(&data->Nl, buffer, size);
+ written += SHA_LONG_Marshal(&data->Nh, buffer, size);
+
+ /* data must be written as array */
+ array_size = sizeof(data->data);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->data[0], array_size,
+ buffer, size);
+
+ written += UINT32_Marshal(&data->num, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+tpmHashStateSHA1_Unmarshal(tpmHashStateSHA1_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ UINT16 array_size;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ HASH_STATE_SHA1_VERSION,
+ HASH_STATE_SHA1_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->h0, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->h1, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->h2, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->h3, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->h4, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->Nl, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->Nh, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != sizeof(data->data)) {
+ TPMLIB_LogTPM2Error("HASH_STATE_SHA1: Bad array size for data; "
+ "expected %zu, got %u\n",
+ sizeof(data->data), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal((BYTE *)&data->data[0], array_size,
+ buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->num, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "HASH_STATE_SHA1", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+#endif
+
+#if ALG_SHA256
+#define HASH_STATE_SHA256_MAGIC 0x6ea059d0
+#define HASH_STATE_SHA256_VERSION 2
+
+static UINT16
+tpmHashStateSHA256_Marshal(tpmHashStateSHA256_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written = 0;
+ UINT16 array_size;
+ size_t i;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ HASH_STATE_SHA256_VERSION,
+ HASH_STATE_SHA256_MAGIC, 1);
+
+ array_size = ARRAY_SIZE(data->h);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++) {
+ written += SHA_LONG_Marshal(&data->h[i], buffer, size);
+ }
+ written += SHA_LONG_Marshal(&data->Nl, buffer, size);
+ written += SHA_LONG_Marshal(&data->Nh, buffer, size);
+
+ /* data must be written as array */
+ array_size = sizeof(data->data);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal((BYTE *)&data->data[0], array_size,
+ buffer, size);
+
+ written += UINT32_Marshal(&data->num, buffer, size);
+ written += UINT32_Marshal(&data->md_len, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+tpmHashStateSHA256_Unmarshal(tpmHashStateSHA256_t *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+ size_t i;
+ UINT16 array_size;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ HASH_STATE_SHA256_VERSION,
+ HASH_STATE_SHA256_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(data->h)) {
+ TPMLIB_LogTPM2Error("HASH_STATE_SHA256: Bad array size for h; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(data->h), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ for (i = 0; rc == TPM_RC_SUCCESS && i < array_size; i++) {
+ rc = SHA_LONG_Unmarshal(&data->h[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->Nl, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG_Unmarshal(&data->Nh, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != sizeof(data->data)) {
+ TPMLIB_LogTPM2Error("HASH_STATE_SHA256: Bad array size for data; "
+ "expected %zu, got %u\n",
+ sizeof(data->data), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal((BYTE *)&data->data[0], array_size,
+ buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->num, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->md_len, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "HASH_STATE_SHA256", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+#endif
+
+#if ALG_SHA384 || ALG_SHA512
+
+#define HASH_STATE_SHA384_MAGIC 0x14814b08
+#define HASH_STATE_SHA384_VERSION 2
+
+#define HASH_STATE_SHA512_MAGIC 0x269e8ae0
+#define HASH_STATE_SHA512_VERSION 2
+
+static UINT16
+tpmHashStateSHA512_Marshal(SHA512_CTX *data, BYTE **buffer, INT32 *size,
+ UINT16 hashAlg)
+{
+ UINT16 written = 0;
+ UINT16 array_size;
+ size_t i;
+ BLOCK_SKIP_INIT;
+ UINT16 version = HASH_STATE_SHA512_VERSION;
+ UINT32 magic = HASH_STATE_SHA512_MAGIC;
+
+ if (hashAlg == ALG_SHA384_VALUE) {
+ version = HASH_STATE_SHA384_VERSION;
+ magic = HASH_STATE_SHA384_MAGIC;
+ }
+
+ written = NV_HEADER_Marshal(buffer, size,
+ version, magic, 1);
+
+ array_size = ARRAY_SIZE(data->h);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++) {
+ written += SHA_LONG64_Marshal(&data->h[i], buffer, size);
+ }
+ written += SHA_LONG64_Marshal(&data->Nl, buffer, size);
+ written += SHA_LONG64_Marshal(&data->Nh, buffer, size);
+
+ array_size = sizeof(data->u.p);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal(&data->u.p[0], array_size, buffer, size);
+
+ written += UINT32_Marshal(&data->num, buffer, size);
+ written += UINT32_Marshal(&data->md_len, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+tpmHashStateSHA512_Unmarshal(SHA512_CTX *data, BYTE **buffer, INT32 *size,
+ UINT16 hashAlg)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+ size_t i;
+ UINT16 array_size;
+ NV_HEADER hdr;
+ UINT16 version = HASH_STATE_SHA512_VERSION;
+ UINT32 magic = HASH_STATE_SHA512_MAGIC;
+
+ if (hashAlg == ALG_SHA384_VALUE) {
+ version = HASH_STATE_SHA384_VERSION;
+ magic = HASH_STATE_SHA384_MAGIC;
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ version, magic);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(data->h)) {
+ TPMLIB_LogTPM2Error("HASH_STATE_SHA512: Bad array size for h; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(data->h), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ for (i = 0; rc == TPM_RC_SUCCESS && i < array_size; i++) {
+ rc = SHA_LONG64_Unmarshal(&data->h[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG64_Unmarshal(&data->Nl, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SHA_LONG64_Unmarshal(&data->Nh, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != sizeof(data->u.p)) {
+ TPMLIB_LogTPM2Error("HASH_STATE_SHA512: Bad array size for u.p; "
+ "expected %zu, got %u\n",
+ sizeof(data->u.p), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal(&data->u.p[0], array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->num, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->md_len, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "HASH_STATE_SHA512", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+#endif
+
+#define ANY_HASH_STATE_MAGIC 0x349d494b
+#define ANY_HASH_STATE_VERSION 2
+
+static UINT16
+ANY_HASH_STATE_Marshal(ANY_HASH_STATE *data, BYTE **buffer, INT32 *size,
+ UINT16 hashAlg)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ ANY_HASH_STATE_VERSION,
+ ANY_HASH_STATE_MAGIC, 1);
+
+ switch (hashAlg) {
+#if ALG_SHA1
+ case ALG_SHA1_VALUE:
+ written += tpmHashStateSHA1_Marshal(&data->Sha1, buffer, size);
+ break;
+#endif
+#if ALG_SHA256
+ case ALG_SHA256_VALUE:
+ written += tpmHashStateSHA256_Marshal(&data->Sha256, buffer, size);
+ break;
+#endif
+#if ALG_SHA384
+ case ALG_SHA384_VALUE:
+ written += tpmHashStateSHA512_Marshal(&data->Sha384, buffer, size,
+ ALG_SHA384_VALUE);
+ break;
+#endif
+#if ALG_SHA512
+ case ALG_SHA512_VALUE:
+ written += tpmHashStateSHA512_Marshal(&data->Sha512, buffer, size,
+ ALG_SHA512_VALUE);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+ANY_HASH_STATE_Unmarshal(ANY_HASH_STATE *data, BYTE **buffer, INT32 *size,
+ UINT16 hashAlg)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ ANY_HASH_STATE_VERSION,
+ ANY_HASH_STATE_MAGIC);
+ }
+
+ switch (hashAlg) {
+#if ALG_SHA1
+ case ALG_SHA1_VALUE:
+ rc = tpmHashStateSHA1_Unmarshal(&data->Sha1, buffer, size);
+ break;
+#endif
+#if ALG_SHA256
+ case ALG_SHA256_VALUE:
+ rc = tpmHashStateSHA256_Unmarshal(&data->Sha256, buffer, size);
+ break;
+#endif
+#if ALG_SHA384
+ case ALG_SHA384_VALUE:
+ rc = tpmHashStateSHA512_Unmarshal(&data->Sha384, buffer, size,
+ ALG_SHA384_VALUE);
+ break;
+#endif
+#if ALG_SHA512
+ case ALG_SHA512_VALUE:
+ rc = tpmHashStateSHA512_Unmarshal(&data->Sha512, buffer, size,
+ ALG_SHA512_VALUE);
+ break;
+#endif
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "ANY_HASH_STATE", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+#define HASH_STATE_MAGIC 0x562878a2
+#define HASH_STATE_VERSION 2
+
+static UINT16
+HASH_STATE_Marshal(HASH_STATE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ HASH_STATE_VERSION,
+ HASH_STATE_MAGIC, 1);
+
+ written += HASH_STATE_TYPE_Marshal(&data->type, buffer, size);
+ written += TPM_ALG_ID_Marshal(&data->hashAlg, buffer, size);
+ /* def does not need to be written */
+ written += ANY_HASH_STATE_Marshal(&data->state, buffer, size, data->hashAlg);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+HASH_STATE_Unmarshal(HASH_STATE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ HASH_STATE_VERSION, HASH_STATE_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = HASH_STATE_TYPE_Unmarshal(&data->type, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->hashAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ data->def = CryptGetHashDef(data->hashAlg);
+ if (!data->def) {
+ TPMLIB_LogTPM2Error("Could not get hash function interface for "
+ "hashAlg 0x%02x\n", data->hashAlg);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = ANY_HASH_STATE_Unmarshal(&data->state, buffer, size, data->hashAlg);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "HASH_STATE", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ return rc;
+}
+
+static inline UINT16
+TPM2B_HASH_BLOCK_Marshal(TPM2B_HASH_BLOCK *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+
+ written = TPM2B_Marshal(&data->b, sizeof(data->t.buffer), buffer, size);
+
+ return written;
+}
+
+static inline UINT16
+TPM2B_HASH_BLOCK_Unmarshal(TPM2B_HASH_BLOCK *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 rc;
+
+ rc = TPM2B_Unmarshal(&data->b, sizeof(data->t.buffer), buffer, size);
+
+ return rc;
+}
+
+static UINT16
+HMAC_STATE_Marshal(HMAC_STATE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+
+ written = HASH_STATE_Marshal(&data->hashState, buffer, size);
+ written += TPM2B_HASH_BLOCK_Marshal(&data->hmacKey, buffer, size);
+
+ return written;
+}
+
+static UINT16
+HMAC_STATE_Unmarshal(HMAC_STATE *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = HASH_STATE_Unmarshal(&data->hashState, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_HASH_BLOCK_Unmarshal(&data->hmacKey, buffer, size);
+ }
+
+ return rc;
+}
+
+#define HASH_OBJECT_MAGIC 0xb874fe38
+#define HASH_OBJECT_VERSION 3
+
+static UINT16
+HASH_OBJECT_Marshal(HASH_OBJECT *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ size_t i;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ HASH_OBJECT_VERSION, HASH_OBJECT_MAGIC, 1);
+ written += TPMI_ALG_PUBLIC_Marshal(&data->type, buffer, size);
+ written += TPMI_ALG_HASH_Marshal(&data->nameAlg, buffer, size);
+ written += TPMA_OBJECT_Marshal(&data->objectAttributes, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->auth, buffer, size);
+ if (data->attributes.hashSeq == SET ||
+ data->attributes.eventSeq == SET /* since v3 */) {
+ array_size = ARRAY_SIZE(data->state.hashState);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ for (i = 0; i < array_size; i++) {
+ written += HASH_STATE_Marshal(&data->state.hashState[i], buffer,
+ size);
+ }
+ } else if (data->attributes.hmacSeq == SET) {
+ written += HMAC_STATE_Marshal(&data->state.hmacState, buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static UINT16
+HASH_OBJECT_Unmarshal(HASH_OBJECT *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ size_t i;
+ UINT16 array_size;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ HASH_OBJECT_VERSION, HASH_OBJECT_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMI_ALG_PUBLIC_Unmarshal(&data->type, buffer, size);
+ if (rc == TPM_RC_TYPE)
+ rc = TPM_RC_SUCCESS;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMI_ALG_HASH_Unmarshal(&data->nameAlg, buffer, size, TRUE);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMA_OBJECT_Unmarshal(&data->objectAttributes, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->auth, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* hashSeq was always written correctly; eventSeq only appeared in v3 */
+ if (data->attributes.hashSeq == SET ||
+ (data->attributes.eventSeq == SET && hdr.version >= 3)) {
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (array_size != ARRAY_SIZE(data->state.hashState)) {
+ TPMLIB_LogTPM2Error("HASH_OBJECT: Bad array size for state.hashState; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(data->state.hashState),
+ array_size);
+ rc = TPM_RC_SIZE;
+ }
+ }
+ for (i = 0; rc == TPM_RC_SUCCESS && i < array_size; i++) {
+ rc = HASH_STATE_Unmarshal(&data->state.hashState[i],
+ buffer, size);
+ }
+ } else if (data->attributes.hmacSeq == SET) {
+ rc = HMAC_STATE_Unmarshal(&data->state.hmacState, buffer, size);
+ }
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "HASH_OBJECT", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+/* Local version of TPMT_SENSITIVE_Marshal handling public keys that don't have much in TPM_SENSITIVE */
+static UINT16
+NV_TPMT_SENSITIVE_Marshal(TPMT_SENSITIVE *source, BYTE **buffer, INT32 *size)
+{
+ UINT16 written = 0;
+
+ written += TPM_ALG_ID_Marshal(&source->sensitiveType, buffer, size);
+ written += TPM2B_AUTH_Marshal(&source->authValue, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&source->seedValue, buffer, size);
+
+ switch (source->sensitiveType) {
+ case TPM_ALG_RSA:
+ case TPM_ALG_ECC:
+ case TPM_ALG_KEYEDHASH:
+ case TPM_ALG_SYMCIPHER:
+ written += TPMU_SENSITIVE_COMPOSITE_Marshal(&source->sensitive, buffer, size, source->sensitiveType);
+ break;
+ default:
+ /* we wrote these but they must have been 0 in this case */
+ pAssert(source->authValue.t.size == 0);
+ pAssert(source->seedValue.t.size == 0);
+ pAssert(source->sensitiveType == TPM_ALG_ERROR)
+ /* public keys */
+ }
+ return written;
+}
+
+/* local version of TPM_SENSITIVE_Unmarshal handling public keys that don't have much in TPMT_SENSITVE */
+static TPM_RC
+NV_TPMT_SENSITIVE_Unmarshal(TPMT_SENSITIVE *target, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+
+ if (rc == TPM_RC_SUCCESS) {
+ /* TPMI_ALG_PUBLIC_Unmarshal would test the sensitiveType; we don't want this */
+ rc = TPM_ALG_ID_Unmarshal(&target->sensitiveType, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&target->authValue, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&target->seedValue, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ switch (target->sensitiveType) {
+ case TPM_ALG_RSA:
+ case TPM_ALG_ECC:
+ case TPM_ALG_KEYEDHASH:
+ case TPM_ALG_SYMCIPHER:
+ rc = TPMU_SENSITIVE_COMPOSITE_Unmarshal(&target->sensitive, buffer, size, target->sensitiveType);
+ break;
+ default:
+ pAssert(target->authValue.t.size == 0);
+ pAssert(target->seedValue.t.size == 0);
+ pAssert(target->sensitiveType == TPM_ALG_ERROR)
+ /* nothing do to do */
+ }
+ }
+ return rc;
+}
+
+#define OBJECT_MAGIC 0x75be73af
+#define OBJECT_VERSION 3
+
+static UINT16
+OBJECT_Marshal(OBJECT *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ BOOL has_block;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ OBJECT_VERSION, OBJECT_MAGIC, 3);
+
+ /*
+ * attributes are written in ANY_OBJECT_Marshal
+ */
+ written += TPMT_PUBLIC_Marshal(&data->publicArea, buffer, size);
+ written += NV_TPMT_SENSITIVE_Marshal(&data->sensitive, buffer, size);
+
+#if ALG_RSA
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+#if ALG_RSA
+ written += privateExponent_t_Marshal(&data->privateExponent,
+ buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ written += TPM2B_NAME_Marshal(&data->qualifiedName, buffer, size);
+ written += TPM_HANDLE_Marshal(&data->evictHandle, buffer, size);
+ written += TPM2B_NAME_Marshal(&data->name, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ written += SEED_COMPAT_LEVEL_Marshal(&data->seedCompatLevel,
+ buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+OBJECT_Unmarshal(OBJECT *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ BOOL needs_block;
+
+ /*
+ * attributes are read in ANY_OBJECT_Unmarshal
+ */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ OBJECT_VERSION, OBJECT_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMT_PUBLIC_Unmarshal(&data->publicArea, buffer, size, TRUE);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_TPMT_SENSITIVE_Unmarshal(&data->sensitive, buffer, size);
+ }
+
+#if ALG_RSA
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_alg_rsa, needs_block, buffer, size,
+ "OBJECT", "privateExponent");
+ }
+#if ALG_RSA
+ if (rc == TPM_RC_SUCCESS) {
+ rc = privateExponent_t_Unmarshal(&data->privateExponent,
+ buffer, size);
+ }
+#endif
+skip_alg_rsa:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_NAME_Unmarshal(&data->qualifiedName, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&data->evictHandle, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_NAME_Unmarshal(&data->name, buffer, size);
+ }
+
+ /* default values before conditional block */
+ data->seedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 3, buffer, size,
+ "OBJECT", "version 3 or later");
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SEED_COMPAT_LEVEL_Unmarshal(&data->seedCompatLevel,
+ buffer, size,
+ "OBJECT seedCompatLevel");
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "OBJECT", "version 4 or later");
+ }
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ return rc;
+}
+
+#define ANY_OBJECT_MAGIC 0xfe9a3974
+#define ANY_OBJECT_VERSION 2
+
+UINT16
+ANY_OBJECT_Marshal(OBJECT *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ UINT32 *ptr = (UINT32 *)&data->attributes;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ ANY_OBJECT_VERSION, ANY_OBJECT_MAGIC, 1);
+
+ written += UINT32_Marshal(ptr, buffer, size);
+ /* the slot must be occupied, otherwise the rest may not be initialized */
+ if (data->attributes.occupied) {
+ if (ObjectIsSequence(data))
+ written += HASH_OBJECT_Marshal((HASH_OBJECT *)data, buffer, size);
+ else
+ written += OBJECT_Marshal(data, buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+TPM_RC
+ANY_OBJECT_Unmarshal(OBJECT *data, BYTE **buffer, INT32 *size, BOOL verbose)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ UINT32 *ptr = (UINT32 *)&data->attributes;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_UnmarshalVerbose(&hdr, buffer, size,
+ ANY_OBJECT_VERSION, ANY_OBJECT_MAGIC,
+ verbose);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(ptr, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS && data->attributes.occupied) {
+ if (ObjectIsSequence(data))
+ rc = HASH_OBJECT_Unmarshal((HASH_OBJECT *)data, buffer, size);
+ else
+ rc = OBJECT_Unmarshal(data, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "ANY_OBJECT", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ return rc;
+}
+
+static UINT16
+TPMT_SYM_DEF_Marshal(TPMT_SYM_DEF *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+
+ written = UINT16_Marshal(&data->algorithm, buffer, size);
+ written += TPMU_SYM_KEY_BITS_Marshal(&data->keyBits, buffer, size, data->algorithm);
+ written += TPMU_SYM_MODE_Marshal(&data->mode, buffer, size, data->algorithm);
+
+ return written;
+}
+
+#define SESSION_MAGIC 0x44be9f45
+#define SESSION_VERSION 2
+
+static UINT16
+SESSION_Marshal(SESSION *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ UINT8 clocksize;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ SESSION_VERSION, SESSION_MAGIC, 1);
+ written += UINT32_Marshal((UINT32 *)&data->attributes, buffer, size);
+ written += UINT32_Marshal(&data->pcrCounter, buffer, size);
+ written += UINT64_Marshal(&data->startTime, buffer, size);
+ written += UINT64_Marshal(&data->timeout, buffer, size);
+
+#if CLOCK_STOPS
+ clocksize = sizeof(UINT64);
+ written += UINT8_Marshal(&clocksize, buffer, size);
+ written += UINT64_Marshal(&data->epoch, buffer, size);
+#else
+ clocksize = sizeof(UINT32);
+ written += UINT8_Marshal(&clocksize, buffer, size);
+ written += UINT32_Marshal(&data->epoch, buffer, size);
+#endif
+
+ written += UINT32_Marshal(&data->commandCode, buffer, size);
+ written += UINT16_Marshal(&data->authHashAlg, buffer, size);
+ written += UINT8_Marshal(&data->commandLocality, buffer, size);
+ written += TPMT_SYM_DEF_Marshal(&data->symmetric, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->sessionKey, buffer, size);
+ written += TPM2B_NONCE_Marshal(&data->nonceTPM, buffer, size);
+ // TPM2B_NAME or TPM2B_DIGEST could be used for marshalling
+ written += TPM2B_NAME_Marshal(&data->u1.boundEntity, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->u2.auditDigest, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+SESSION_Unmarshal(SESSION *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ UINT8 clocksize;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ SESSION_VERSION, SESSION_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal((UINT32 *)&data->attributes, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->pcrCounter, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->startTime, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->timeout, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT8_Unmarshal(&clocksize, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+#if CLOCK_STOPS
+ if (clocksize != sizeof(UINT64)) {
+ TPMLIB_LogTPM2Error("Unexpected clocksize for epoch; "
+ "Expected %zu, got %u\n",
+ sizeof(UINT64), clocksize);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->epoch, buffer, size);
+ }
+#else
+ if (clocksize != sizeof(UINT32)) {
+ TPMLIB_LogTPM2Error("Unexpected clocksize for epoch; "
+ "Expected %zu, got %u\n",
+ sizeof(UINT32), clocksize);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->epoch, buffer, size);
+ }
+#endif
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->commandCode, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&data->authHashAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT8_Unmarshal(&data->commandLocality, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMT_SYM_DEF_Unmarshal(&data->symmetric, buffer, size, YES);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->sessionKey, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_NONCE_Unmarshal(&data->nonceTPM, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_NAME_Unmarshal(&data->u1.boundEntity, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->u2.auditDigest, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "SESSION", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ return rc;
+}
+
+#define SESSION_SLOT_MAGIC 0x3664aebc
+#define SESSION_SLOT_VERSION 2
+
+static UINT16
+SESSION_SLOT_Marshal(SESSION_SLOT *data, BYTE **buffer, INT32* size)
+{
+ UINT16 written;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ SESSION_SLOT_VERSION,
+ SESSION_SLOT_MAGIC, 1);
+
+ written += BOOL_Marshal(&data->occupied, buffer, size);
+ if (!data->occupied)
+ return written;
+
+ written += SESSION_Marshal(&data->session, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+SESSION_SLOT_Unmarshal(SESSION_SLOT *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ SESSION_SLOT_VERSION, SESSION_SLOT_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->occupied, buffer, size);
+ }
+ if (!data->occupied)
+ return rc;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SESSION_Unmarshal(&data->session, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "SESSION_SLOT", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ return rc;
+}
+
+#define VOLATILE_STATE_VERSION 4
+#define VOLATILE_STATE_MAGIC 0x45637889
+
+UINT16
+VolatileState_Marshal(BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ size_t i;
+ BOOL tpmEst;
+ UINT64 tmp_uint64;
+ UINT32 tmp_uint32;
+ BOOL has_block;
+ UINT16 array_size;
+ BLOCK_SKIP_INIT;
+ PERSISTENT_DATA pd;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ VOLATILE_STATE_VERSION, VOLATILE_STATE_MAGIC,
+ 1);
+
+ /* skip g_rcIndex: these are 'constants' */
+ written += TPM_HANDLE_Marshal(&g_exclusiveAuditSession, buffer, size); /* line 423 */
+ /* g_time: may not be necessary */
+ written += UINT64_Marshal(&g_time, buffer, size); /* line 426 */
+ /* g_timeEpoch: skipped so far -- needs investigation */
+ /* g_phEnable: since we won't call TPM2_Starup, we need to write it */
+ written += BOOL_Marshal(&g_phEnable, buffer, size); /* line 439 */
+ /* g_pcrReconfig: must write */
+ written += BOOL_Marshal(&g_pcrReConfig, buffer, size); /* line 443 */
+ /* g_DRTMHandle: must write */
+ written += TPM_HANDLE_Marshal(&g_DRTMHandle, buffer, size); /* line 448 */
+ /* g_DrtmPreStartup: must write */
+ written += BOOL_Marshal(&g_DrtmPreStartup, buffer, size); /* line 453 */
+ /* g_StartupLocality3: must write */
+ written += BOOL_Marshal(&g_StartupLocality3, buffer, size); /* line 458 */
+
+#if USE_DA_USED
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if USE_DA_USED
+ /* g_daUsed: must write */
+ written += BOOL_Marshal(&g_daUsed, buffer, size); /* line 484 */
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ /* g_updateNV: can skip since it seems to only be valid during execution of a command*/
+ /* g_powerWasLost: must write */
+ written += BOOL_Marshal(&g_powerWasLost, buffer, size); /* line 504 */
+ /* g_clearOrderly: can skip since it seems to only be valid during execution of a command */
+ /* g_prevOrderlyState: must write */
+ written += UINT16_Marshal(&g_prevOrderlyState, buffer, size); /* line 516 */
+ /* g_nvOk: must write */
+ written += BOOL_Marshal(&g_nvOk, buffer, size); /* line 522 */
+ /* g_NvStatus: can skip since it seems to only be valid during execution of a command */
+
+#if 0 /* does not exist */
+ written += TPM2B_AUTH_Marshal(&g_platformUniqueAuthorities, buffer, size); /* line 535 */
+#endif
+ written += TPM2B_AUTH_Marshal(&g_platformUniqueDetails, buffer, size); /* line 536 */
+
+ /* gp (persistent_data): skip; we assume its latest states in the persistent data file */
+
+ /* we store the next 3 because they may not have been written to NVRAM */
+ written += ORDERLY_DATA_Marshal(&go, buffer, size); /* line 707 */
+ written += STATE_CLEAR_DATA_Marshal(&gc, buffer, size); /* line 738 */
+ written += STATE_RESET_DATA_Marshal(&gr, buffer, size); /* line 826 */
+
+ /* g_manufactured: must write */
+ written += BOOL_Marshal(&g_manufactured, buffer, size); /* line 928 */
+ /* g_initialized: must write */
+ written += BOOL_Marshal(&g_initialized, buffer, size); /* line 932 */
+
+#if defined SESSION_PROCESS_C || defined GLOBAL_C || defined MANUFACTURE_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined SESSION_PROCESS_C || defined GLOBAL_C || defined MANUFACTURE_C
+ /*
+ * The session related variables may only be valid during the execution
+ * of a single command; safer to store
+ */
+ array_size = ARRAY_SIZE(s_sessionHandles);
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ written += TPM_HANDLE_Marshal(&s_sessionHandles[i], buffer, size);
+ written += TPMA_SESSION_Marshal(&s_attributes[i], buffer, size);
+ written += TPM_HANDLE_Marshal(&s_associatedHandles[i], buffer, size);
+ written += TPM2B_NONCE_Marshal(&s_nonceCaller[i], buffer, size);
+ written += TPM2B_AUTH_Marshal(&s_inputAuthValues[i], buffer, size);
+ /* s_usedSessions: cannot serialize this since it is a pointer; also, isn't used */
+ }
+ written += TPM_HANDLE_Marshal(&s_encryptSessionIndex, buffer, size);
+ written += TPM_HANDLE_Marshal(&s_decryptSessionIndex, buffer, size);
+ written += TPM_HANDLE_Marshal(&s_auditSessionIndex, buffer, size);
+
+#if CC_GetCommandAuditDigest
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if CC_GetCommandAuditDigest
+ /* s_cpHashForCommandAudit: seems not used; better to write it */
+ written += TPM2B_DIGEST_Marshal(&s_cpHashForCommandAudit, buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ /* s_DAPendingOnNV: needs investigation ... */
+ written += BOOL_Marshal(&s_DAPendingOnNV, buffer, size);
+#endif // SESSION_PROCESS_C
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined DA_C || defined GLOBAL_C || defined MANUFACTURE_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined DA_C || defined GLOBAL_C || defined MANUFACTURE_C
+
+#if !ACCUMULATE_SELF_HEAL_TIMER
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if !ACCUMULATE_SELF_HEAL_TIMER
+ written += UINT64_Marshal(&s_selfHealTimer, buffer, size); /* line 975 */
+ written += UINT64_Marshal(&s_lockoutTimer, buffer, size); /* line 977 */
+#endif // ACCUMULATE_SELF_HEAL_TIMER
+ BLOCK_SKIP_WRITE_POP(size);
+#endif // DA_C
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined NV_C || defined GLOBAL_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+ /* s_evictNvEnd set in NvInitStatic called by NvPowerOn in case g_powerWasLost
+ * Unless we set g_powerWasLost=TRUE and call NvPowerOn, we have to include it.
+ */
+#if defined NV_C || defined GLOBAL_C
+ written += UINT32_Marshal(&s_evictNvEnd, buffer, size); /* line 984 */
+ /* s_indexOrderlyRam read from NVRAM in NvEntityStartup and written to it
+ * in NvUpdateIndexOrderlyData called by TPM2_Shutdown and initialized
+ * in NvManufacture -- since we don't call TPM2_Shutdown we serialize it here
+ */
+ array_size = sizeof(s_indexOrderlyRam);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal(s_indexOrderlyRam, array_size, buffer, size);
+
+ written += UINT64_Marshal(&s_maxCounter, buffer, size); /* line 992 */
+ /* the following need not be written; NvIndexCacheInit initializes them partly
+ * and NvIndexCacheInit() is called during ExecuteCommand()
+ * - s_cachedNvIndex
+ * - s_cachedNvRef
+ * - s_cachedNvRamRef
+ */
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined OBJECT_C || defined GLOBAL_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined OBJECT_C || defined GLOBAL_C
+ /* used in many places; it doesn't look like TPM2_Shutdown writes this into
+ * persistent memory, so what is lost upon TPM2_Shutdown?
+ */
+ array_size = ARRAY_SIZE(s_objects);
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ written += ANY_OBJECT_Marshal(&s_objects[i], buffer, size);
+ }
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined PCR_C || defined GLOBAL_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined PCR_C || defined GLOBAL_C
+ /* s_pcrs: Marshal *all* PCRs, even those for which stateSave bit is not set */
+ array_size = ARRAY_SIZE(s_pcrs);
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ written += PCR_Marshal(&s_pcrs[i], buffer, size);
+ }
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined SESSION_C || defined GLOBAL_C
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined SESSION_C || defined GLOBAL_C
+ /* s_sessions: */
+ array_size = ARRAY_SIZE(s_sessions);
+ written += UINT16_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ written += SESSION_SLOT_Marshal(&s_sessions[i], buffer, size);
+ }
+ /* s_oldestSavedSession: */
+ written += UINT32_Marshal(&s_oldestSavedSession, buffer, size);
+ /* s_freeSessionSlots: */
+ written += UINT32_Marshal((UINT32 *)&s_freeSessionSlots, buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+#if defined IO_BUFFER_C || defined GLOBAL_C
+ /* s_actionInputBuffer: skip; only used during a single command */
+ /* s_actionOutputBuffer: skip; only used during a single command */
+#endif
+ written += BOOL_Marshal(&g_inFailureMode, buffer, size); /* line 1078 */
+
+ /* TPM established bit */
+ tpmEst = _rpc__Signal_GetTPMEstablished();
+ written += BOOL_Marshal(&tpmEst, buffer, size);
+
+#if defined TPM_FAIL_C || defined GLOBAL_C || 1
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined TPM_FAIL_C || defined GLOBAL_C || 1
+ written += UINT32_Marshal(&s_failFunction, buffer, size);
+ written += UINT32_Marshal(&s_failLine, buffer, size);
+ written += UINT32_Marshal(&s_failCode, buffer, size);
+#endif // TPM_FAIL_C
+ BLOCK_SKIP_WRITE_POP(size);
+
+#ifndef HARDWARE_CLOCK
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#ifndef HARDWARE_CLOCK
+ tmp_uint64 = s_realTimePrevious;
+ written += UINT64_Marshal(&tmp_uint64, buffer, size);
+ tmp_uint64 = s_tpmTime;
+ written += UINT64_Marshal(&tmp_uint64, buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ written += BOOL_Marshal(&s_timerReset, buffer, size);
+ written += BOOL_Marshal(&s_timerStopped, buffer, size);
+ written += UINT32_Marshal(&s_adjustRate, buffer, size);
+
+ tmp_uint64 = ClockGetTime(CLOCK_REALTIME);
+ written += UINT64_Marshal(&tmp_uint64, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v3 */
+
+ /* tie the volatile state to the EP,SP, and PPSeed */
+ NvRead(&pd, NV_PERSISTENT_DATA, sizeof(pd));
+ written += TPM2B_Marshal(&pd.EPSeed.b, sizeof(pd.EPSeed.t.buffer), buffer, size);
+ written += TPM2B_Marshal(&pd.SPSeed.b, sizeof(pd.SPSeed.t.buffer), buffer, size);
+ written += TPM2B_Marshal(&pd.PPSeed.b, sizeof(pd.PPSeed.t.buffer), buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v4 */
+
+ tmp_uint64 = ClockGetTime(CLOCK_MONOTONIC) + s_hostMonotonicAdjustTime;
+ written += UINT64_Marshal(&tmp_uint64, buffer, size);
+
+ written += UINT64_Marshal(&s_suspendedElapsedTime, buffer, size);
+ written += UINT64_Marshal(&s_lastSystemTime, buffer, size);
+ written += UINT64_Marshal(&s_lastReportedTime, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v5 */
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size); /* v5 */
+ BLOCK_SKIP_WRITE_POP(size); /* v4 */
+ BLOCK_SKIP_WRITE_POP(size); /* v3 */
+
+ /* keep marker at end */
+ tmp_uint32 = VOLATILE_STATE_MAGIC;
+ written += UINT32_Marshal(&tmp_uint32, buffer, size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+VolatileState_TailV4_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ UINT64 tmp_uint64;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&tmp_uint64, buffer, size);
+ s_hostMonotonicAdjustTime = tmp_uint64 - ClockGetTime(CLOCK_MONOTONIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_suspendedElapsedTime, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_lastSystemTime, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_lastReportedTime, buffer, size);
+ }
+
+ return rc;
+}
+
+static TPM_RC
+VolatileState_TailV3_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ PERSISTENT_DATA pd;
+ TPM2B_SEED seed = {
+ .b.size = 0,
+ };
+
+ NvRead(&pd, NV_PERSISTENT_DATA, sizeof(pd));
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&seed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (seed.b.size > PRIMARY_SEED_SIZE) /* coverity */
+ rc = TPM_RC_SIZE;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (TPM2B_Cmp(&seed.b, &pd.EPSeed.b)) {
+ TPMLIB_LogTPM2Error("%s: EPSeed does not match\n",
+ __func__);
+ rc = TPM_RC_VALUE;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&seed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (seed.b.size > PRIMARY_SEED_SIZE) /* coverity */
+ rc = TPM_RC_SIZE;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (TPM2B_Cmp(&seed.b, &pd.SPSeed.b)) {
+ TPMLIB_LogTPM2Error("%s: SPSeed does not match\n",
+ __func__);
+ rc = TPM_RC_VALUE;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&seed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (seed.b.size > PRIMARY_SEED_SIZE) /* coverity */
+ rc = TPM_RC_SIZE;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (TPM2B_Cmp(&seed.b, &pd.PPSeed.b)) {
+ TPMLIB_LogTPM2Error("%s: PPSeed does not match\n",
+ __func__);
+ rc = TPM_RC_VALUE;
+ }
+ }
+
+ return rc;
+}
+
+TPM_RC
+VolatileState_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ size_t i;
+ UINT64 tmp_uint64;
+ UINT32 tmp_uint32;
+ NV_HEADER hdr;
+ BOOL needs_block;
+ UINT16 array_size = 0;
+ UINT64 backthen;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ VOLATILE_STATE_VERSION, VOLATILE_STATE_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&g_exclusiveAuditSession, buffer, size); /* line 423 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&g_time, buffer, size); /* line 426 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_phEnable, buffer, size); /* line 439 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_pcrReConfig, buffer, size); /* line 443 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&g_DRTMHandle, buffer, size); /* line 448 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_DrtmPreStartup, buffer, size); /* line 453 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_StartupLocality3, buffer, size); /* line 458 */
+ }
+
+#if USE_DA_USED
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_da, needs_block, buffer, size,
+ "Volatile state", "g_daUsed");
+ }
+#if USE_DA_USED
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_daUsed, buffer, size); /* line 484 */
+ }
+#endif
+skip_da:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_powerWasLost, buffer, size); /* line 504 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&g_prevOrderlyState, buffer, size); /* line 516 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_nvOk, buffer, size); /* line 522 */
+ }
+#if 0 /* does not exist */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&g_platformUniqueAuthorities, buffer, size); /* line 535 */
+ }
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&g_platformUniqueDetails, buffer, size); /* line 536 */
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = ORDERLY_DATA_Unmarshal(&go, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = STATE_CLEAR_DATA_Unmarshal(&gc, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = STATE_RESET_DATA_Unmarshal(&gr, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_manufactured, buffer, size); /* line 928 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_initialized, buffer, size); /* line 932 */
+ }
+
+#if defined SESSION_PROCESS_C || defined GLOBAL_C || defined MANUFACTURE_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_session_process, needs_block, buffer, size,
+ "Volatile state", "s_sessionHandles");
+ }
+#if defined SESSION_PROCESS_C || defined GLOBAL_C || defined MANUFACTURE_C
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(s_sessionHandles)) {
+ TPMLIB_LogTPM2Error("Volatile state: Bad array size for s_sessionHandles; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(s_sessionHandles), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&s_sessionHandles[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMA_SESSION_Unmarshal(&s_attributes[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&s_associatedHandles[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_NONCE_Unmarshal(&s_nonceCaller[i], buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[i], buffer, size);
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&s_encryptSessionIndex, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&s_decryptSessionIndex, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&s_auditSessionIndex, buffer, size);
+ }
+
+#if CC_GetCommandAuditDigest
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_cc_getcommandauditdigest, needs_block, buffer, size,
+ "Volatile state", "s_cpHashForCommandAudit");
+ }
+#if CC_GetCommandAuditDigest
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&s_cpHashForCommandAudit, buffer, size);
+ }
+#endif
+skip_cc_getcommandauditdigest:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&s_DAPendingOnNV, buffer, size);
+ }
+#endif /* SESSION_PROCESS_C */
+skip_session_process:
+
+#if defined DA_C || defined GLOBAL_C || defined MANUFACTURE_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_accumulate_self_heal_timer_1, needs_block, buffer, size,
+ "Volatile state", "s_selfHealTimer.1");
+ }
+
+#if defined DA_C || defined GLOBAL_C || defined MANUFACTURE_C
+#if !ACCUMULATE_SELF_HEAL_TIMER
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_accumulate_self_heal_timer_2, needs_block, buffer, size,
+ "Volatile state", "s_selfHealTimer.2");
+ }
+#if !ACCUMULATE_SELF_HEAL_TIMER
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_selfHealTimer, buffer, size); /* line 975 */
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_lockoutTimer, buffer, size); /* line 977 */
+ }
+#endif
+skip_accumulate_self_heal_timer_2:
+#endif
+skip_accumulate_self_heal_timer_1:
+
+#if defined NV_C || defined GLOBAL_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_nv, needs_block, buffer, size,
+ "Volatile state", "s_evictNvEnd");
+ }
+
+#if defined NV_C || defined GLOBAL_C
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_evictNvEnd, buffer, size); /* line 984 */
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(s_indexOrderlyRam)) {
+ TPMLIB_LogTPM2Error("Volatile state: Bad array size for s_indexOrderlyRam; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(s_indexOrderlyRam), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = Array_Unmarshal(s_indexOrderlyRam, array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&s_maxCounter, buffer, size); /* line 992 */
+ }
+ /* The following are not included:
+ * - s_cachedNvIndex
+ * - s_cachedNvRef
+ * - s_cachedNvRamRef
+ */
+#endif
+skip_nv:
+
+#if defined OBJECT_C || defined GLOBAL_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_object, needs_block, buffer, size,
+ "Volatile state", "s_objects");
+ }
+#if defined OBJECT_C || defined GLOBAL_C
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(s_objects)) {
+ TPMLIB_LogTPM2Error("Volatile state: Bad array size for s_objects; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(s_objects), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ rc = ANY_OBJECT_Unmarshal(&s_objects[i], buffer, size, true);
+ }
+#endif
+skip_object:
+
+#if defined PCR_C || defined GLOBAL_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_pcr, needs_block, buffer, size,
+ "Volatile state", "s_pcrs");
+ }
+#if defined PCR_C || defined GLOBAL_C
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(s_pcrs)) {
+ TPMLIB_LogTPM2Error("Volatile state: Bad array size for s_pcrs; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(s_pcrs), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ rc = PCR_Unmarshal(&s_pcrs[i], buffer, size, &shadow.pcrAllocated);
+ }
+#endif
+skip_pcr:
+
+#if defined SESSION_C || defined GLOBAL_C
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_session, needs_block, buffer, size,
+ "Volatile state", "s_sessions");
+ }
+#if defined SESSION_C || defined GLOBAL_C
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != ARRAY_SIZE(s_sessions)) {
+ TPMLIB_LogTPM2Error("Volatile state: Bad array size for s_sessions; "
+ "expected %zu, got %u\n",
+ ARRAY_SIZE(s_sessions), array_size);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ /* s_sessions: */
+ for (i = 0; i < array_size && rc == TPM_RC_SUCCESS; i++) {
+ rc = SESSION_SLOT_Unmarshal(&s_sessions[i], buffer, size);
+ }
+ /* s_oldestSavedSession: */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_oldestSavedSession, buffer, size);
+ }
+ /* s_freeSessionSlots: */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal((UINT32 *)&s_freeSessionSlots, buffer, size);
+ }
+#endif
+skip_session:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&g_inFailureMode, buffer, size); /* line 1078 */
+ }
+
+ /* TPM established bit */
+ if (rc == TPM_RC_SUCCESS) {
+ BOOL tpmEst;
+ rc = BOOL_Unmarshal(&tpmEst, buffer, size);
+ if (rc == TPM_RC_SUCCESS) {
+ if (tpmEst)
+ _rpc__Signal_SetTPMEstablished();
+ else
+ _rpc__Signal_ResetTPMEstablished();
+ }
+ }
+
+#if defined TPM_FAIL_C || defined GLOBAL_C || 1
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_fail, needs_block, buffer, size,
+ "Volatile state", "s_failFunction");
+ }
+
+#if defined TPM_FAIL_C || defined GLOBAL_C || 1
+ /* appended in v2 */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_failFunction, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_failLine, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_failCode, buffer, size);
+ }
+#endif
+skip_fail:
+
+#ifndef HARDWARE_CLOCK
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_hardware_clock, needs_block, buffer, size,
+ "Volatile state", "s_realTimePrevious");
+ }
+
+#ifndef HARDWARE_CLOCK
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&tmp_uint64, buffer, size);
+ s_realTimePrevious = tmp_uint64;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&tmp_uint64, buffer, size);
+ s_tpmTime = tmp_uint64;
+ }
+#endif
+skip_hardware_clock:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&s_timerReset, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&s_timerStopped, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&s_adjustRate, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&backthen, buffer, size);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 3, buffer, size,
+ "Volatile State", "version 3 or later");
+ if (rc == TPM_RC_SUCCESS) {
+ rc = VolatileState_TailV3_Unmarshal(buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 4, buffer, size,
+ "Volatile State", "version 4 or later");
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = VolatileState_TailV4_Unmarshal(buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "Volatile State", "version 5 or later");
+ }
+ /* future versions append here */
+ }
+
+skip_future_versions:
+
+ /* keep marker at end: */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&tmp_uint32, buffer, size);
+ if (rc == TPM_RC_SUCCESS) {
+ if (tmp_uint32 != VOLATILE_STATE_MAGIC) {
+ TPMLIB_LogTPM2Error("Invalid volatile state magic. "
+ "Expected 0x%08x, got 0x%08x\n",
+ VOLATILE_STATE_MAGIC, tmp_uint32);
+ rc = TPM_RC_BAD_TAG;
+ }
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ BOOL timesAreRealtime = hdr.version <= 3;
+ /* Before Rev148 (header version <= 3), times were reported in
+ realtime; we need to account for this now */
+ ClockAdjustPostResume(backthen, timesAreRealtime);
+ }
+ return rc;
+}
+
+/********************************************************************
+ * The following is a list of compile-time constants that we verify against
+ * when state is presented to us. Comparison operators allow us to verify
+ * compile time constants' values against what we would accept when reading
+ * state. So for example a value of 1024 for a buffer size that is read can
+ * be compared against the value that this implementation has been compiled
+ * with. In some case a 'less or equal' [LE] (1024 < 2048) may be acceptable
+ * but that depends on the purpose of the compile time constant. The most
+ * conservative approach is to force that the unmarshalled values are equal
+ * [EQ] to the ones of this implementation.
+ *
+ * Meanings of comparison operators:
+ * EQ: The read state must match the state the implementation would produce
+ * The algorithm must have been enabled at the previously implementation
+ * and at the current implementation; or it must have been disabled at
+ * both
+ *
+ * LE: The read state may have been written by a version that did not
+ * implement an algorithm ('0') but the current implementation does
+ * implement it ('1'); this does NOT allow an implementation to accept
+ * the state anymore if the state was written by an implementation that
+ * implemented it ('1') but the current implementation does not im-
+ * plement it
+ *
+ * DONTCARE: Implementation that wrote the state can either have implemented
+ * an algorithm or not and implementation reading the state may
+ * also either implement it or not
+ */
+static const struct _entry {
+ UINT32 constant;
+ char *name;
+ enum CompareOp { EQ, LE, GE, DONTCARE } cmp;
+} pa_compile_constants[] = {
+#define COMPILE_CONSTANT(CONST, CMP) \
+ .constant = CONST, .name = #CONST, .cmp = CMP
+ { COMPILE_CONSTANT(ALG_RSA, EQ) },
+ { COMPILE_CONSTANT(ALG_SHA1, EQ) },
+ { COMPILE_CONSTANT(ALG_HMAC, EQ) },
+ { COMPILE_CONSTANT(ALG_TDES, LE) },
+ { COMPILE_CONSTANT(ALG_AES, EQ) },
+ { COMPILE_CONSTANT(ALG_MGF1, EQ) },
+ { COMPILE_CONSTANT(ALG_XOR, EQ) },
+ { COMPILE_CONSTANT(ALG_KEYEDHASH, EQ) },
+ { COMPILE_CONSTANT(ALG_SHA256, EQ) },
+ { COMPILE_CONSTANT(ALG_SHA384, EQ) },
+ { COMPILE_CONSTANT(ALG_SHA512, EQ) },
+ { COMPILE_CONSTANT(ALG_SM3_256, EQ) },
+ { COMPILE_CONSTANT(ALG_SM4, EQ) },
+ { COMPILE_CONSTANT(ALG_RSASSA, EQ) },
+ { COMPILE_CONSTANT(ALG_RSAES, EQ) },
+ { COMPILE_CONSTANT(ALG_RSAPSS, EQ) },
+ { COMPILE_CONSTANT(ALG_OAEP, EQ) },
+ { COMPILE_CONSTANT(ALG_ECC, EQ) },
+ { COMPILE_CONSTANT(ALG_ECDH, EQ) },
+ { COMPILE_CONSTANT(ALG_ECDSA, EQ) },
+ { COMPILE_CONSTANT(ALG_ECDAA, EQ) },
+ { COMPILE_CONSTANT(ALG_SM2, LE) },
+ { COMPILE_CONSTANT(ALG_ECSCHNORR, EQ) },
+ { COMPILE_CONSTANT(ALG_ECMQV, LE) },
+ { COMPILE_CONSTANT(ALG_SYMCIPHER, EQ) },
+ { COMPILE_CONSTANT(ALG_KDF1_SP800_56A, EQ) },
+ { COMPILE_CONSTANT(ALG_KDF2, LE) },
+ { COMPILE_CONSTANT(ALG_KDF1_SP800_108, EQ) },
+ { COMPILE_CONSTANT(ALG_CMAC, LE) },
+ { COMPILE_CONSTANT(ALG_CTR, EQ) },
+ { COMPILE_CONSTANT(ALG_OFB, EQ) },
+ { COMPILE_CONSTANT(ALG_CBC, EQ) },
+ { COMPILE_CONSTANT(ALG_CFB, EQ) },
+ { COMPILE_CONSTANT(ALG_ECB, EQ) },
+ { COMPILE_CONSTANT(MAX_RSA_KEY_BITS, LE) }, /* old: 2048 */
+ { COMPILE_CONSTANT(MAX_TDES_KEY_BITS, EQ) },
+ { COMPILE_CONSTANT(MAX_AES_KEY_BITS, EQ) },
+ { COMPILE_CONSTANT(128, EQ) }, /* MAX_SM4_KEY_BITS in older code was 128 also with SM4 not active */
+ { COMPILE_CONSTANT(128, EQ) }, /* MAX_CAMELLIA_KEY_BITS in older code was 128 also with CAMELLIA not active */
+ { COMPILE_CONSTANT(ECC_NIST_P192, LE) },
+ { COMPILE_CONSTANT(ECC_NIST_P224, LE) },
+ { COMPILE_CONSTANT(ECC_NIST_P256, LE) },
+ { COMPILE_CONSTANT(ECC_NIST_P384, LE) },
+ { COMPILE_CONSTANT(ECC_NIST_P521, LE) },
+ { COMPILE_CONSTANT(ECC_BN_P256, LE) },
+ { COMPILE_CONSTANT(ECC_BN_P638, LE) },
+ { COMPILE_CONSTANT(ECC_SM2_P256, LE) },
+ { COMPILE_CONSTANT(MAX_ECC_KEY_BITS, LE) },
+ { COMPILE_CONSTANT(4, EQ) }, /* was: HASH_ALIGNMENT, which is not relevant */
+ { COMPILE_CONSTANT(SYM_ALIGNMENT, EQ) },
+ { COMPILE_CONSTANT(IMPLEMENTATION_PCR, EQ) },
+ { COMPILE_CONSTANT(PLATFORM_PCR, EQ) },
+ { COMPILE_CONSTANT(DRTM_PCR, EQ) },
+ { COMPILE_CONSTANT(HCRTM_PCR, EQ) },
+ { COMPILE_CONSTANT(NUM_LOCALITIES, EQ) },
+ { COMPILE_CONSTANT(MAX_HANDLE_NUM, EQ) },
+ { COMPILE_CONSTANT(MAX_ACTIVE_SESSIONS, EQ) },
+ { COMPILE_CONSTANT(MAX_LOADED_SESSIONS, EQ) },
+ { COMPILE_CONSTANT(MAX_SESSION_NUM, EQ) },
+ { COMPILE_CONSTANT(MAX_LOADED_OBJECTS, EQ) },
+ { COMPILE_CONSTANT(MIN_EVICT_OBJECTS, LE) },
+ { COMPILE_CONSTANT(NUM_POLICY_PCR_GROUP, EQ) },
+ { COMPILE_CONSTANT(NUM_AUTHVALUE_PCR_GROUP, EQ) },
+ { COMPILE_CONSTANT(MAX_CONTEXT_SIZE, LE) }, /* old: 2474 */
+ { COMPILE_CONSTANT(MAX_DIGEST_BUFFER, EQ) },
+ { COMPILE_CONSTANT(MAX_NV_INDEX_SIZE, EQ) },
+ { COMPILE_CONSTANT(MAX_NV_BUFFER_SIZE, EQ) },
+ { COMPILE_CONSTANT(MAX_CAP_BUFFER, EQ) },
+ { COMPILE_CONSTANT(NV_MEMORY_SIZE, LE) },
+ { COMPILE_CONSTANT(MIN_COUNTER_INDICES, EQ) },
+ { COMPILE_CONSTANT(NUM_STATIC_PCR, EQ) },
+ { COMPILE_CONSTANT(MAX_ALG_LIST_SIZE, EQ) },
+ { COMPILE_CONSTANT(PRIMARY_SEED_SIZE, EQ) },
+#if CONTEXT_ENCRYPT_ALGORITHM == AES
+#define CONTEXT_ENCRYPT_ALGORITHM_ TPM_ALG_AES
+#endif
+ { COMPILE_CONSTANT(CONTEXT_ENCRYPT_ALGORITHM_, EQ) },
+ { COMPILE_CONSTANT(NV_CLOCK_UPDATE_INTERVAL, EQ) },
+ { COMPILE_CONSTANT(NUM_POLICY_PCR, EQ) },
+ { COMPILE_CONSTANT(ORDERLY_BITS, EQ) },
+ { COMPILE_CONSTANT(MAX_SYM_DATA, EQ) },
+ { COMPILE_CONSTANT(MAX_RNG_ENTROPY_SIZE, EQ) },
+ { COMPILE_CONSTANT(RAM_INDEX_SPACE, EQ) },
+ { COMPILE_CONSTANT(RSA_DEFAULT_PUBLIC_EXPONENT, EQ) },
+ { COMPILE_CONSTANT(ENABLE_PCR_NO_INCREMENT, EQ) },
+ { COMPILE_CONSTANT(CRT_FORMAT_RSA, EQ) },
+ { COMPILE_CONSTANT(VENDOR_COMMAND_COUNT, EQ) },
+ { COMPILE_CONSTANT(MAX_VENDOR_BUFFER_SIZE, EQ) },
+ { COMPILE_CONSTANT(TPM_MAX_DERIVATION_BITS, EQ) },
+ { COMPILE_CONSTANT(PROOF_SIZE, EQ) },
+ { COMPILE_CONSTANT(HASH_COUNT, EQ) },
+
+ /* added for PA_COMPILE_CONSTANTS_VERSION == 3 */
+ { COMPILE_CONSTANT(AES_128, LE) },
+ { COMPILE_CONSTANT(AES_192, LE) },
+ { COMPILE_CONSTANT(AES_256, LE) },
+ { COMPILE_CONSTANT(SM4_128, LE) },
+ { COMPILE_CONSTANT(ALG_CAMELLIA, LE) },
+ { COMPILE_CONSTANT(CAMELLIA_128, LE) },
+ { COMPILE_CONSTANT(CAMELLIA_192, LE) },
+ { COMPILE_CONSTANT(CAMELLIA_256, LE) },
+ { COMPILE_CONSTANT(ALG_SHA3_256, LE) },
+ { COMPILE_CONSTANT(ALG_SHA3_384, LE) },
+ { COMPILE_CONSTANT(ALG_SHA3_512, LE) },
+ { COMPILE_CONSTANT(RSA_1024, LE) },
+ { COMPILE_CONSTANT(RSA_2048, LE) },
+ { COMPILE_CONSTANT(RSA_3072, LE) },
+ { COMPILE_CONSTANT(RSA_4096, LE) },
+ { COMPILE_CONSTANT(RSA_16384, LE) },
+ { COMPILE_CONSTANT(RH_ACT_0, LE) },
+ { COMPILE_CONSTANT(RH_ACT_1, LE) },
+ { COMPILE_CONSTANT(RH_ACT_2, LE) },
+ { COMPILE_CONSTANT(RH_ACT_3, LE) },
+ { COMPILE_CONSTANT(RH_ACT_4, LE) },
+ { COMPILE_CONSTANT(RH_ACT_5, LE) },
+ { COMPILE_CONSTANT(RH_ACT_6, LE) },
+ { COMPILE_CONSTANT(RH_ACT_7, LE) },
+ { COMPILE_CONSTANT(RH_ACT_8, LE) },
+ { COMPILE_CONSTANT(RH_ACT_9, LE) },
+ { COMPILE_CONSTANT(RH_ACT_A, LE) },
+ { COMPILE_CONSTANT(RH_ACT_B, LE) },
+ { COMPILE_CONSTANT(RH_ACT_C, LE) },
+ { COMPILE_CONSTANT(RH_ACT_D, LE) },
+ { COMPILE_CONSTANT(RH_ACT_E, LE) },
+ { COMPILE_CONSTANT(RH_ACT_F, LE) },
+};
+
+static TPM_RC
+UINT32_Unmarshal_CheckConstant(BYTE **buffer, INT32 *size, UINT32 constant,
+ const char *name,
+ enum CompareOp cmp, UINT16 struct_version)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ UINT32 value;
+ const char *op = NULL;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&value, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ switch (cmp) {
+ case EQ:
+ if (!(constant == value))
+ op = "=";
+ break;
+ case LE:
+ if (!(value <= constant))
+ op = "<=";
+ break;
+ case GE:
+ if (!(value >= constant))
+ op = ">=";
+ break;
+ case DONTCARE:
+ break;
+ }
+ if (op) {
+ TPMLIB_LogTPM2Error("Unexpected value for %s; "
+ "its value %d is not %s %d; "
+ "(version: %u)\n",
+ name, value, op, constant,
+ struct_version);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ }
+ return rc;
+}
+
+#define PA_COMPILE_CONSTANTS_MAGIC 0xc9ea6431
+#define PA_COMPILE_CONSTANTS_VERSION 3
+
+/* Marshal compile-time constants related to persistent-all state */
+static UINT32
+PACompileConstants_Marshal(BYTE **buffer, INT32 *size)
+{
+ unsigned i;
+ UINT32 written, tmp_uint32;
+ UINT32 array_size = ARRAY_SIZE(pa_compile_constants);
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PA_COMPILE_CONSTANTS_VERSION,
+ PA_COMPILE_CONSTANTS_MAGIC, 1);
+
+ written += UINT32_Marshal(&array_size, buffer, size);
+
+ for (i = 0; i < array_size; i++) {
+ tmp_uint32 = pa_compile_constants[i].constant;
+ written += UINT32_Marshal(&tmp_uint32, buffer, size);
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+PACompileConstants_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ unsigned i;
+ NV_HEADER hdr;
+ UINT32 array_size;
+ UINT32 exp_array_size = 0;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PA_COMPILE_CONSTANTS_VERSION,
+ PA_COMPILE_CONSTANTS_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ switch (hdr.version) {
+ case 1:
+ case 2:
+ /* PA_COMPILE_CONSTANTS_VERSION 1 and 2 had 88 entries */
+ exp_array_size = 88;
+ break;
+ case 3:
+ /* PA_COMPILE_CONSTANTS_VERSION 3 had 104 entries */
+ exp_array_size = 120;
+ break;
+ default:
+ /* we don't suport anything newer - no downgrade */
+ TPMLIB_LogTPM2Error("Unsupported PA_COMPILE_CONSTANTS version %d. "
+ "Supporting up to version %d.\n",
+ hdr.version, PA_COMPILE_CONSTANTS_VERSION);
+ rc = TPM_RC_BAD_VERSION;
+ }
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&array_size, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS &&
+ array_size != exp_array_size) {
+ TPMLIB_LogTPM2Error("PA_COMPILE_CONSTANTS v%d has non-matching number of "
+ "elements; found %u, expected %u\n",
+ hdr.version, array_size, exp_array_size);
+ }
+
+ for (i = 0; rc == TPM_RC_SUCCESS && i < exp_array_size; i++)
+ rc = UINT32_Unmarshal_CheckConstant(
+ buffer, size, pa_compile_constants[i].constant,
+ pa_compile_constants[i].name,
+ pa_compile_constants[i].cmp, hdr.version);
+
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PA_COMPILE_CONSTANTS", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ /* keep marker at end: */
+ return rc;
+}
+
+#define PERSISTENT_DATA_MAGIC 0x12213443
+#define PERSISTENT_DATA_VERSION 4
+
+static UINT16
+PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ UINT16 array_size;
+ UINT8 clocksize;
+ BOOL has_block;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PERSISTENT_DATA_VERSION,
+ PERSISTENT_DATA_MAGIC, 4);
+ written += BOOL_Marshal(&data->disableClear, buffer, size);
+ written += TPM_ALG_ID_Marshal(&data->ownerAlg, buffer, size);
+ written += TPM_ALG_ID_Marshal(&data->endorsementAlg, buffer, size);
+ written += TPM_ALG_ID_Marshal(&data->lockoutAlg, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->ownerPolicy, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->endorsementPolicy, buffer, size);
+ written += TPM2B_DIGEST_Marshal(&data->lockoutPolicy, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->ownerAuth, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->endorsementAuth, buffer, size);
+ written += TPM2B_AUTH_Marshal(&data->lockoutAuth, buffer, size);
+ written += TPM2B_Marshal(&data->EPSeed.b, sizeof(data->EPSeed.t.buffer), buffer, size);
+ written += TPM2B_Marshal(&data->SPSeed.b, sizeof(data->SPSeed.t.buffer), buffer, size);
+ written += TPM2B_Marshal(&data->PPSeed.b, sizeof(data->PPSeed.t.buffer), buffer, size);
+ written += TPM2B_PROOF_Marshal(&data->phProof, buffer, size);
+ written += TPM2B_PROOF_Marshal(&data->shProof, buffer, size);
+ written += TPM2B_PROOF_Marshal(&data->ehProof, buffer, size);
+ written += UINT64_Marshal(&data->totalResetCount, buffer, size);
+ written += UINT32_Marshal(&data->resetCount, buffer, size);
+
+#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
+ has_block = TRUE;
+#else
+ has_block = FALSE;
+#endif
+ written += BLOCK_SKIP_WRITE_PUSH(has_block, buffer, size);
+
+#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
+ written += PCR_POLICY_Marshal(&data->pcrPolicies, buffer, size);
+#endif
+ BLOCK_SKIP_WRITE_POP(size);
+
+ written += TPML_PCR_SELECTION_Marshal(&data->pcrAllocated, buffer, size);
+
+ /* ppList may grow */
+ array_size = sizeof(data->ppList);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal(&data->ppList[0], array_size, buffer, size);
+
+ written += UINT32_Marshal(&data->failedTries, buffer, size);
+ written += UINT32_Marshal(&data->maxTries, buffer, size);
+ written += UINT32_Marshal(&data->recoveryTime, buffer, size);
+ written += UINT32_Marshal(&data->lockoutRecovery, buffer, size);
+ written += BOOL_Marshal(&data->lockOutAuthEnabled, buffer, size);
+ written += UINT16_Marshal(&data->orderlyState, buffer, size);
+
+ /* auditCommands may grow */
+ array_size = sizeof(data->auditCommands);
+ written += UINT16_Marshal(&array_size, buffer, size);
+ written += Array_Marshal(&data->auditCommands[0], array_size,
+ buffer, size);
+
+ written += TPM_ALG_ID_Marshal(&data->auditHashAlg, buffer, size);
+ written += UINT64_Marshal(&data->auditCounter, buffer, size);
+ written += UINT32_Marshal(&data->algorithmSet, buffer, size);
+ written += UINT32_Marshal(&data->firmwareV1, buffer, size);
+ written += UINT32_Marshal(&data->firmwareV2, buffer, size);
+#if CLOCK_STOPS
+ clocksize = sizeof(UINT64);
+ written += UINT8_Marshal(&clocksize, buffer, size);
+ written += UINT64_Marshal(&data->timeEpoch, buffer, size);
+#else
+ clocksize = sizeof(UINT32);
+ written += UINT8_Marshal(&clocksize, buffer, size);
+ written += UINT32_Marshal(&data->timeEpoch, buffer, size);
+#endif
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+
+ /* there's a 'shadow' pcrAllocated as well */
+ written += TPML_PCR_SELECTION_Marshal(&gp.pcrAllocated, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ written += SEED_COMPAT_LEVEL_Marshal(&data->EPSeedCompatLevel,
+ buffer, size);
+ written += SEED_COMPAT_LEVEL_Marshal(&data->SPSeedCompatLevel,
+ buffer, size);
+ written += SEED_COMPAT_LEVEL_Marshal(&data->PPSeedCompatLevel,
+ buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+ BLOCK_SKIP_WRITE_POP(size);
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+PERSISTENT_DATA_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ UINT16 array_size;
+ UINT8 clocksize;
+ BOOL needs_block;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PERSISTENT_DATA_VERSION,
+ PERSISTENT_DATA_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->disableClear, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->ownerAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->endorsementAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->lockoutAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->ownerPolicy, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->endorsementPolicy, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_DIGEST_Unmarshal(&data->lockoutPolicy, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->ownerAuth, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->endorsementAuth, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_AUTH_Unmarshal(&data->lockoutAuth, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&data->EPSeed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&data->SPSeed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_Unmarshal(&data->PPSeed.b, PRIMARY_SEED_SIZE, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_PROOF_Unmarshal(&data->phProof, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_PROOF_Unmarshal(&data->shProof, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM2B_PROOF_Unmarshal(&data->ehProof, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->totalResetCount, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->resetCount, buffer, size);
+ }
+
+#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
+ needs_block = TRUE;
+#else
+ needs_block = FALSE;
+#endif
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_num_policy_pcr_group, needs_block, buffer, size,
+ "PERSISTENT_DATA", "pcrPolicies");
+ }
+#if defined NUM_POLICY_PCR_GROUP && NUM_POLICY_PCR_GROUP > 0
+ if (rc == TPM_RC_SUCCESS) {
+ rc = PCR_POLICY_Unmarshal(&data->pcrPolicies, buffer, size);
+ }
+#endif
+skip_num_policy_pcr_group:
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPML_PCR_SELECTION_Unmarshal(&data->pcrAllocated, buffer, size);
+
+ shadow.pcrAllocated = data->pcrAllocated;
+ shadow.pcrAllocatedIsNew = TRUE;
+ }
+
+ /* ppList array may not be our size */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ BYTE buf[array_size];
+ rc = Array_Unmarshal(buf, array_size, buffer, size);
+ memcpy(data->ppList, buf, MIN(array_size, sizeof(data->ppList)));
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->failedTries, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->maxTries, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->recoveryTime, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->lockoutRecovery, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = BOOL_Unmarshal(&data->lockOutAuthEnabled, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* TPM_SU_Unmarshal returns error if value is 0 */
+ rc = UINT16_Unmarshal(&data->orderlyState, buffer, size);
+ }
+
+ /* auditCommands array may not be our size */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&array_size, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ BYTE buf[array_size];
+ rc = Array_Unmarshal(buf, array_size, buffer, size);
+ memcpy(data->auditCommands, buf,
+ MIN(array_size, sizeof(data->auditCommands)));
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_ALG_ID_Unmarshal(&data->auditHashAlg, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->auditCounter, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->algorithmSet, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->firmwareV1, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->firmwareV2, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT8_Unmarshal(&clocksize, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+#if CLOCK_STOPS
+ if (clocksize != sizeof(UINT64)) {
+ TPMLIB_LogTPM2Error("Unexpected clocksize for epoch; "
+ "Expected %u, got %u\n",
+ sizeof(UINT64), clocksize);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&data->timeEpoch, buffer, size);
+ }
+#else
+ if (clocksize != sizeof(UINT32)) {
+ TPMLIB_LogTPM2Error("Unexpected clocksize for epoch; "
+ "Expected %zu, got %u\n",
+ sizeof(UINT32), clocksize);
+ rc = TPM_RC_BAD_PARAMETER;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&data->timeEpoch, buffer, size);
+ }
+#endif
+ }
+
+ /* default values before conditional block */
+ data->EPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
+ data->SPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
+ data->PPSeedCompatLevel = SEED_COMPAT_LEVEL_ORIGINAL;
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 3, buffer, size,
+ "PERSISTENT_DATA", "version 3 or later");
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPML_PCR_SELECTION_Unmarshal(&shadow.pcrAllocated, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 4, buffer, size,
+ "PERSISTENT_DATA", "version 4 or later");
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SEED_COMPAT_LEVEL_Unmarshal(&data->EPSeedCompatLevel,
+ buffer, size, "EPSeed");
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SEED_COMPAT_LEVEL_Unmarshal(&data->SPSeedCompatLevel,
+ buffer, size, "SPSeed");
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = SEED_COMPAT_LEVEL_Unmarshal(&data->PPSeedCompatLevel,
+ buffer, size, "PPSeed");
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "PERSISTENT_DATA", "version 5 or later");
+ }
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ if (rc != TPM_RC_SUCCESS) {
+ TPMLIB_LogTPM2Error("Failed to unmarshal PERSISTENT_DATA version %u\n",
+ hdr.version);
+ }
+ return rc;
+}
+
+#define INDEX_ORDERLY_RAM_VERSION 2
+#define INDEX_ORDERLY_RAM_MAGIC 0x5346feab
+static UINT32
+INDEX_ORDERLY_RAM_Marshal(void *array, size_t array_size,
+ BYTE **buffer, INT32 *size)
+{
+ UINT16 written;
+ NV_RAM_HEADER nrh, *nrhp;
+ UINT16 offset = 0;
+ UINT16 datasize;
+ UINT32 sourceside_size = array_size;
+ BLOCK_SKIP_INIT;
+
+ written = NV_HEADER_Marshal(buffer, size,
+ INDEX_ORDERLY_RAM_VERSION,
+ INDEX_ORDERLY_RAM_MAGIC, 1);
+
+ /* the size of the array we are using here */
+ written += UINT32_Marshal(&sourceside_size, buffer, size);
+
+ while (TRUE) {
+ nrhp = array + offset;
+ /* nrhp may point to misaligned address (ubsan), so use 'nrh'; first access only 'size' */
+ memcpy(&nrh, nrhp, sizeof(nrh.size));
+
+ /* write the NVRAM header;
+ nrh->size holds the complete size including data;
+ nrh->size = 0 indicates the end */
+ written += UINT32_Marshal(&nrh.size, buffer, size);
+ if (nrh.size == 0)
+ break;
+ /* copy the entire structure now; ubsan does not allow 'nrh = *nrhp' */
+ memcpy(&nrh, nrhp, sizeof(nrh));
+
+ written += TPM_HANDLE_Marshal(&nrh.handle, buffer, size);
+ written += TPMA_NV_Marshal(&nrh.attributes, buffer, size);
+
+ if (offset + nrh.size > array_size) {
+ TPMLIB_LogTPM2Error("INDEX_ORDERLY_RAM: nrh->size corrupted: %d\n",
+ nrh.size);
+ break;
+ }
+ /* write data size before array */
+ if (nrh.size < sizeof(NV_RAM_HEADER)) {
+ TPMLIB_LogTPM2Error(
+ "INDEX_ORDERLY_RAM: nrh->size < sizeof(NV_RAM_HEADER): %d < %zu\n",
+ (int)nrh.size, sizeof(NV_RAM_HEADER));
+ break;
+ }
+ datasize = nrh.size - sizeof(NV_RAM_HEADER);
+ written += UINT16_Marshal(&datasize, buffer, size);
+ if (datasize > 0) {
+ /* append the data */
+ written += Array_Marshal(array + offset + sizeof(NV_RAM_HEADER),
+ datasize, buffer, size);
+ }
+ offset += nrh.size;
+ if (offset + sizeof(NV_RAM_HEADER) > array_size) {
+ /* nothing will fit anymore and there won't be a 0-sized
+ * terminating node (@1).
+ */
+ break;
+ }
+ }
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+static TPM_RC
+INDEX_ORDERLY_RAM_Unmarshal(void *array, size_t array_size,
+ BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ NV_RAM_HEADER nrh, *nrhp;
+ UINT16 offset = 0;
+ UINT16 datasize = 0;
+ UINT32 sourceside_size;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ INDEX_ORDERLY_RAM_VERSION,
+ INDEX_ORDERLY_RAM_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* get the size of the array on the source side
+ we can accommodate different sizes when rebuilding
+ but if it doesn't fit we'll error out and report the sizes */
+ rc = UINT32_Unmarshal(&sourceside_size, buffer, size);
+ }
+
+ while (rc == TPM_RC_SUCCESS) {
+ memset(&nrh, 0, sizeof(nrh)); /* coverity */
+ /* nrhp may point to misaligned address (ubsan)
+ * we read 'into' nrh and copy to nrhp at end
+ */
+ nrhp = array + offset;
+
+ if (offset + sizeof(NV_RAM_HEADER) > sourceside_size) {
+ /* this case can occur with the previous entry filling up the
+ * space; in this case there will not be a 0-sized terminating
+ * node (see @1 above). We clear the rest of our space.
+ */
+ if (array_size > offset)
+ memset(nrhp, 0, array_size - offset);
+ break;
+ }
+
+ /* write the NVRAM header;
+ nrh->size holds the complete size including data;
+ nrh->size = 0 indicates the end */
+ if (offset + sizeof(nrh.size) > array_size) {
+ offset += sizeof(nrh.size);
+ goto exit_size;
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&nrh.size, buffer, size);
+ if (rc == TPM_RC_SUCCESS && nrh.size == 0) {
+ memcpy(nrhp, &nrh, sizeof(nrh.size));
+ break;
+ }
+ }
+ if (offset + sizeof(NV_RAM_HEADER) > array_size) {
+ offset += sizeof(NV_RAM_HEADER);
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&nrh.handle, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPMA_NV_Unmarshal(&nrh.attributes, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT16_Unmarshal(&datasize, buffer, size);
+ }
+ if (offset + sizeof(NV_RAM_HEADER) + datasize > array_size) {
+ offset += sizeof(NV_RAM_HEADER) + datasize;
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS && datasize > 0) {
+ /* append the data */
+ rc = Array_Unmarshal(array + offset + sizeof(NV_RAM_HEADER),
+ datasize, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* fix up size in case it is architecture-dependent */
+ nrh.size = sizeof(nrh) + datasize;
+ offset += nrh.size;
+ /* copy header into possibly misaligned address in NVRAM */
+ *nrhp = nrh;
+ }
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "INDEX_ORDERLY_RAM", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ return rc;
+
+exit_size:
+ TPMLIB_LogTPM2Error("INDEX_ORDERLY_RAM:"
+ "Insufficient space to write to offset %u;"
+ "Source had %u bytes, we have %zu bytes.\n",
+ offset, sourceside_size, array_size);
+ return TPM_RC_SIZE;
+}
+
+static void
+USER_NVRAM_Display(const char *msg)
+{
+ NV_REF entryRef = NV_USER_DYNAMIC;
+ UINT32 entrysize;
+ UINT64 offset = 0;
+ TPM_HANDLE handle;
+ UINT32 datasize;
+ NV_INDEX nvi;
+ OBJECT obj;
+ UINT64 maxCount;
+
+ fprintf(stderr, "USER_NVRAM contents %s:\n", msg);
+
+ while (TRUE) {
+ /* 1st: entrysize */
+ NvRead(&entrysize, entryRef, sizeof(entrysize));
+ fprintf(stderr, " offset: %5"PRIu32" entry size: %5u ",
+ (UINT32)(entryRef - NV_USER_DYNAMIC), entrysize);
+ offset = sizeof(UINT32);
+
+ if (entrysize == 0)
+ break;
+
+ /* 2nd: the handle -- it will tell us what datatype this is */
+ NvRead(&handle, entryRef + offset, sizeof(handle));
+ fprintf(stderr, "handle: 0x%08x ", handle);
+
+ switch (HandleGetType(handle)) {
+ case TPM_HT_NV_INDEX:
+ fprintf(stderr, " (NV_INDEX) ");
+ /* NV_INDEX has the index again at offset 0! */
+ NvReadNvIndexInfo(entryRef + offset, &nvi);
+ offset += sizeof(nvi);
+ datasize = entrysize - sizeof(UINT32) - sizeof(nvi);
+ fprintf(stderr, " datasize: %u\n",datasize);
+ break;
+ break;
+ case TPM_HT_PERSISTENT:
+ fprintf(stderr, " (PERSISTENT)");
+ offset += sizeof(handle);
+
+ NvRead(&obj, entryRef + offset, sizeof(obj));
+ offset += sizeof(obj);
+ fprintf(stderr, " sizeof(obj): %zu\n", sizeof(obj));
+ break;
+ default:
+ TPMLIB_LogTPM2Error("USER_NVRAM: Corrupted handle: %08x\n", handle);
+ }
+ /* advance to next entry */
+ entryRef += entrysize;
+ }
+ fprintf(stderr, "\n");
+
+ NvRead(&maxCount, entryRef + offset, sizeof(maxCount));
+ fprintf(stderr, " maxCount: %"PRIu64"\n", maxCount);
+ fprintf(stderr, "-----------------------------\n");
+}
+
+#define USER_NVRAM_VERSION 2
+#define USER_NVRAM_MAGIC 0x094f22c3
+static UINT32
+USER_NVRAM_Marshal(BYTE **buffer, INT32 *size)
+{
+ UINT32 written;
+ UINT32 entrysize;
+ UINT64 offset;
+ NV_REF entryRef = NV_USER_DYNAMIC;
+ NV_INDEX nvi;
+ UINT64 maxCount;
+ TPM_HANDLE handle;
+ OBJECT obj;
+ UINT32 datasize;
+ UINT64 sourceside_size = NV_USER_DYNAMIC_END - NV_USER_DYNAMIC;
+ BLOCK_SKIP_INIT;
+
+ if (FALSE)
+ USER_NVRAM_Display("before marshalling");
+
+ written = NV_HEADER_Marshal(buffer, size,
+ USER_NVRAM_VERSION, USER_NVRAM_MAGIC,
+ 1);
+
+ written += UINT64_Marshal(&sourceside_size, buffer, size);
+
+ while (TRUE) {
+ /* 1st: entrysize */
+ NvRead(&entrysize, entryRef, sizeof(entrysize));
+ offset = sizeof(UINT32);
+
+ /* entrysize is in native format now */
+ written += UINT32_Marshal(&entrysize, buffer, size);
+ if (entrysize == 0)
+ break;
+
+ /* 2nd: the handle -- it will tell us what datatype this is */
+ NvRead(&handle, entryRef + offset, sizeof(handle));
+ written += TPM_HANDLE_Marshal(&handle, buffer, size);
+
+ switch (HandleGetType(handle)) {
+ case TPM_HT_NV_INDEX:
+ /* NV_INDEX has the index again at offset 0! */
+ NvReadNvIndexInfo(entryRef + offset, &nvi);
+ offset += sizeof(nvi);
+
+ written += NV_INDEX_Marshal(&nvi, buffer, size);
+ /* after that: bulk data */
+ datasize = entrysize - sizeof(UINT32) - sizeof(nvi);
+ written += UINT32_Marshal(&datasize, buffer, size);
+ if (datasize > 0) {
+ BYTE buf[datasize];
+ NvRead(buf, entryRef + offset, datasize);
+ written += Array_Marshal(buf, datasize, buffer, size);
+ }
+ break;
+ case TPM_HT_PERSISTENT:
+ offset += sizeof(handle);
+
+ NvRead(&obj, entryRef + offset, sizeof(obj));
+ offset += sizeof(obj);
+ written += ANY_OBJECT_Marshal(&obj, buffer, size);
+ break;
+ default:
+ TPMLIB_LogTPM2Error("USER_NVRAM: Corrupted handle: %08x\n", handle);
+ }
+ /* advance to next entry */
+ entryRef += entrysize;
+ }
+ NvRead(&maxCount, entryRef + offset, sizeof(maxCount));
+ written += UINT64_Marshal(&maxCount, buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+/*
+ * USER_NVRAM_Unmarshal:
+ *
+ * Unmarshal the byte stream directly into the NVRAM. Ensure that the
+ * the data fit into the user NVRAM before writing them.
+ *
+ * This function fails if there's not enough NVRAM to write the data into
+ * or if an unknown handle type was encountered.
+ */
+static TPM_RC
+USER_NVRAM_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ NV_REF entryRef = NV_USER_DYNAMIC;
+ UINT32 entrysize;
+ UINT64 offset, o = 0;
+ NV_INDEX nvi;
+ UINT64 maxCount;
+ TPM_HANDLE handle;
+ OBJECT obj;
+ UINT32 datasize = 0;
+ UINT64 sourceside_size;
+ UINT64 array_size = NV_USER_DYNAMIC_END - NV_USER_DYNAMIC;
+ UINT64 entrysize_offset;
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ USER_NVRAM_VERSION,
+ USER_NVRAM_MAGIC);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&sourceside_size, buffer, size);
+ }
+
+ while (rc == TPM_RC_SUCCESS) {
+ /* 1st: entrysize */
+ if (o + sizeof(UINT32) > array_size) {
+ o += sizeof(UINT32);
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&entrysize, buffer, size);
+
+ /* the entrysize also depends on the sizeof(nvi); we may have to
+ update it if sizeof(nvi) changed between versions */
+ entrysize_offset = o;
+ NvWrite(entryRef + o, sizeof(entrysize), &entrysize);
+ offset = sizeof(UINT32);
+ if (entrysize == 0)
+ break;
+ }
+ /* 2nd: handle */
+ if (rc == TPM_RC_SUCCESS) {
+ rc = TPM_HANDLE_Unmarshal(&handle, buffer, size);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ switch (HandleGetType(handle)) {
+ case TPM_HT_NV_INDEX:
+ /* we need to read the handle again */
+ if (rc == TPM_RC_SUCCESS &&
+ o + offset + sizeof(nvi) > array_size) {
+ o += offset + sizeof(nvi);
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_INDEX_Unmarshal(&nvi, buffer, size);
+ NvWrite(entryRef + o + offset, sizeof(nvi), &nvi);
+ offset += sizeof(nvi);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal(&datasize, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* datasize cannot exceed 64k + a few bytes */
+ if (datasize > (0x10000 + 0x100)) {
+ TPMLIB_LogTPM2Error("datasize for NV_INDEX too "
+ "large: %u\n", datasize);
+ rc = TPM_RC_SIZE;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ o + offset + datasize > array_size) {
+ o += offset + datasize;
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS && datasize > 0) {
+ BYTE buf[datasize];
+ rc = Array_Unmarshal(buf, datasize, buffer, size);
+ NvWrite(entryRef + o + offset, datasize, buf);
+ offset += datasize;
+
+ /* update the entry size; account for expanding nvi */
+ entrysize = sizeof(UINT32) + sizeof(nvi) + datasize;
+ }
+ break;
+ case TPM_HT_PERSISTENT:
+ if (rc == TPM_RC_SUCCESS &&
+ o + offset + sizeof(TPM_HANDLE) + sizeof(obj) >
+ array_size) {
+ o += offset + sizeof(TPM_HANDLE) + sizeof(obj);
+ goto exit_size;
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ NvWrite(entryRef + o + offset, sizeof(handle), &handle);
+ offset += sizeof(TPM_HANDLE);
+
+ memset(&obj, 0, sizeof(obj));
+ rc = ANY_OBJECT_Unmarshal(&obj, buffer, size, true);
+ NvWrite(entryRef + o + offset, sizeof(obj), &obj);
+ offset += sizeof(obj);
+ }
+ entrysize = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(obj);
+ break;
+ default:
+ TPMLIB_LogTPM2Error("USER_NVRAM: "
+ "Read handle 0x%08x of unknown type\n",
+ handle);
+ rc = TPM_RC_HANDLE;
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ NvWrite(entryRef + entrysize_offset, sizeof(entrysize), &entrysize);
+ }
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ o += offset;
+ }
+ }
+ if (rc == TPM_RC_SUCCESS &&
+ o + offset + sizeof(UINT64) > array_size) {
+ o += offset + sizeof(UINT64);
+ goto exit_size;
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT64_Unmarshal(&maxCount, buffer, size);
+ NvWrite(entryRef + o + offset, sizeof(maxCount), &maxCount);
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "USER_NVRAM", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+
+ if (FALSE)
+ USER_NVRAM_Display("after unmarshalling");
+
+ return rc;
+
+exit_size:
+ TPMLIB_LogTPM2Error("USER_NVRAM:"
+ "Insufficient space to write to offset %"PRIu64";"
+ "Source had %"PRIu64" bytes, we have %"PRIu64" "
+ "bytes.\n",
+ o, sourceside_size, array_size);
+ return TPM_RC_SIZE;
+}
+
+/*
+ * Write out all persistent data by reading them from the NVRAM
+ * and then writing them out.
+ *
+ * - PERSISTENT_DATA (NV_PERSISTENT_DATA)
+ * - ORDERLY_DATA (NV_STATE_RESET_DATA)
+ * - STATE_RESET_DATA (NV_STATE_RESET_DATA)
+ * - STATE_CLEAR_DATA (NV_STATE_CLEAR_DATA)
+ * - indexOrderlyRAM (NV_INDEX_RAM_DATA)
+ * - NVRAM locations (NV_USER_DYNAMIC)
+ */
+#define PERSISTENT_ALL_VERSION 3
+#define PERSISTENT_ALL_MAGIC 0xab364723
+UINT32
+PERSISTENT_ALL_Marshal(BYTE **buffer, INT32 *size)
+{
+ UINT32 magic;
+ PERSISTENT_DATA pd;
+ ORDERLY_DATA od;
+ STATE_RESET_DATA srd;
+ STATE_CLEAR_DATA scd;
+ UINT32 written = 0;
+ BYTE indexOrderlyRam[sizeof(s_indexOrderlyRam)];
+ BLOCK_SKIP_INIT;
+ BOOL writeSuState;
+
+ NvRead(&pd, NV_PERSISTENT_DATA, sizeof(pd));
+ NvRead(&od, NV_ORDERLY_DATA, sizeof(od));
+ NvRead(&srd, NV_STATE_RESET_DATA, sizeof(srd));
+ NvRead(&scd, NV_STATE_CLEAR_DATA, sizeof(scd));
+
+ /* indexOrderlyRam was never endianess-converted; so it's native */
+ NvRead(indexOrderlyRam, NV_INDEX_RAM_DATA, sizeof(indexOrderlyRam));
+
+ written = NV_HEADER_Marshal(buffer, size,
+ PERSISTENT_ALL_VERSION,
+ PERSISTENT_ALL_MAGIC, 3);
+ written += PACompileConstants_Marshal(buffer, size);
+ written += PERSISTENT_DATA_Marshal(&pd, buffer, size);
+ written += ORDERLY_DATA_Marshal(&od, buffer, size);
+ writeSuState = (pd.orderlyState & TPM_SU_STATE_MASK) == TPM_SU_STATE;
+ /* starting with v3 we only write STATE_RESET and STATE_CLEAR if needed */
+ if (writeSuState) {
+ written += STATE_RESET_DATA_Marshal(&srd, buffer, size);
+ written += STATE_CLEAR_DATA_Marshal(&scd, buffer, size);
+ }
+ written += INDEX_ORDERLY_RAM_Marshal(indexOrderlyRam, sizeof(indexOrderlyRam),
+ buffer, size);
+ written += USER_NVRAM_Marshal(buffer, size);
+
+ written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+ /* future versions append below this line */
+
+ BLOCK_SKIP_WRITE_POP(size);
+
+ magic = PERSISTENT_ALL_MAGIC;
+ written += UINT32_Marshal(&magic, buffer, size);
+
+ BLOCK_SKIP_WRITE_CHECK;
+
+ return written;
+}
+
+TPM_RC
+PERSISTENT_ALL_Unmarshal(BYTE **buffer, INT32 *size)
+{
+ TPM_RC rc = TPM_RC_SUCCESS;
+ NV_HEADER hdr;
+ PERSISTENT_DATA pd;
+ ORDERLY_DATA od;
+ STATE_RESET_DATA srd;
+ STATE_CLEAR_DATA scd;
+ BYTE indexOrderlyRam[sizeof(s_indexOrderlyRam)];
+ BOOL readSuState = false;
+
+ memset(&pd, 0, sizeof(pd));
+ memset(&od, 0, sizeof(od));
+ memset(&srd, 0, sizeof(srd));
+ memset(&scd, 0, sizeof(scd));
+ memset(indexOrderlyRam, 0, sizeof(indexOrderlyRam));
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+ PERSISTENT_ALL_VERSION,
+ PERSISTENT_ALL_MAGIC);
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ rc = PACompileConstants_Unmarshal(buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = PERSISTENT_DATA_Unmarshal(&pd, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ if (hdr.version < 3) {
+ /* STATE_RESET and STATE_CLEAR were always written before version 3 */
+ readSuState = true;
+ } else {
+ readSuState = (pd.orderlyState & TPM_SU_STATE_MASK) == TPM_SU_STATE;
+ }
+ rc = ORDERLY_DATA_Unmarshal(&od, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && readSuState) {
+ rc = STATE_RESET_DATA_Unmarshal(&srd, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS && readSuState) {
+ rc = STATE_CLEAR_DATA_Unmarshal(&scd, buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ rc = INDEX_ORDERLY_RAM_Unmarshal(indexOrderlyRam, sizeof(indexOrderlyRam),
+ buffer, size);
+ }
+ if (rc == TPM_RC_SUCCESS) {
+ /* this will write it into NVRAM right away */
+ rc = USER_NVRAM_Unmarshal(buffer, size);
+ /* if rc == TPM_RC_SUCCESS, we know that there is enough
+ NVRAM to fit everything. */
+ }
+
+ /* version 2 starts having indicator for next versions that we can skip;
+ this allows us to downgrade state */
+ if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+ BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+ "USER NVRAM", "version 3 or later");
+ /* future versions nest-append here */
+ }
+
+skip_future_versions:
+ if (rc == TPM_RC_SUCCESS) {
+ rc = UINT32_Unmarshal_Check(&hdr.magic,
+ PERSISTENT_ALL_MAGIC, buffer, size,
+ "PERSISTENT_ALL_MAGIC after USER_NVRAM");
+ }
+
+ if (rc == TPM_RC_SUCCESS) {
+ NvWrite(NV_PERSISTENT_DATA, sizeof(pd), &pd);
+ NvWrite(NV_ORDERLY_DATA, sizeof(od), &od);
+ NvWrite(NV_STATE_RESET_DATA, sizeof(srd), &srd);
+ NvWrite(NV_STATE_CLEAR_DATA, sizeof(scd), &scd);
+ NvWrite(NV_INDEX_RAM_DATA, sizeof(indexOrderlyRam), indexOrderlyRam);
+ }
+
+ return rc;
+}
+
+void
+NVShadowRestore(void)
+{
+ if (shadow.pcrAllocatedIsNew) {
+ gp.pcrAllocated = shadow.pcrAllocated;
+ shadow.pcrAllocatedIsNew = FALSE;
+ }
+}