summaryrefslogtreecommitdiffstats
path: root/src/tpm_tpm2_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm_tpm2_interface.c')
-rw-r--r--src/tpm_tpm2_interface.c690
1 files changed, 690 insertions, 0 deletions
diff --git a/src/tpm_tpm2_interface.c b/src/tpm_tpm2_interface.c
new file mode 100644
index 0000000..8d8117e
--- /dev/null
+++ b/src/tpm_tpm2_interface.c
@@ -0,0 +1,690 @@
+/********************************************************************************/
+/* */
+/* LibTPM TPM 2 call interface functions */
+/* Written by Stefan Berger */
+/* IBM Thomas J. Watson Research Center */
+/* */
+/* (c) Copyright IBM Corporation 2015. */
+/* */
+/* 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 <config.h>
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#ifndef LIB_EXPORT
+#define LIB_EXPORT
+#endif
+#include "tpm2/Tpm.h"
+#include "tpm2/Manufacture_fp.h"
+#include "tpm2/Platform_fp.h"
+#include "tpm2/ExecCommand_fp.h"
+#include "tpm2/TpmTcpProtocol.h"
+#include "tpm2/Simulator_fp.h"
+#include "tpm2/_TPM_Hash_Data_fp.h"
+#include "tpm2/_TPM_Init_fp.h"
+#include "tpm2/StateMarshal.h"
+#include "tpm2/PlatformACT.h"
+#include "tpm2/PlatformData.h"
+#include "tpm2/Volatile.h"
+#include "tpm2/crypto/openssl/ExpDCache_fp.h"
+
+#define TPM_HAVE_TPM2_DECLARATIONS
+#include "tpm_nvfile.h" // TPM_NVRAM_Loaddata()
+#include "tpm_error.h"
+#include "tpm_library_intern.h"
+#include "tpm_nvfilename.h"
+
+extern BOOL g_inFailureMode;
+static BOOL reportedFailureCommand;
+
+/*
+ * Check whether the main NVRAM file exists. Return TRUE if it doesn, FALSE otherwise
+ */
+static TPM_BOOL _TPM2_CheckNVRAMFileExists(bool *has_nvram_loaddata_callback)
+{
+#ifdef TPM_LIBTPMS_CALLBACKS
+ struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
+ const char *name = TPM_PERMANENT_ALL_NAME;
+ unsigned char *data = NULL;
+ uint32_t length = 0;
+ uint32_t tpm_number = 0;
+ TPM_RESULT ret;
+
+ *has_nvram_loaddata_callback = cbs->tpm_nvram_loaddata != NULL;
+ if (cbs->tpm_nvram_loaddata) {
+ ret = cbs->tpm_nvram_loaddata(&data, &length, tpm_number, name);
+ free(data);
+ /* a file exists once NOT TPM_RETRY is returned */
+ if (ret != TPM_RETRY)
+ return TRUE;
+ }
+#else
+ *has_nvram_loaddata_callback = FALSE;
+#endif /* TPM_LIBTPMS_CALLBACKS */
+
+ return FALSE;
+}
+
+static TPM_RESULT TPM2_MainInit(void)
+{
+ TPM_RESULT ret = TPM_SUCCESS;
+ bool has_cached_state;
+ bool has_nvram_file;
+ bool has_nvram_loaddata_callback;
+
+ g_inFailureMode = FALSE;
+ reportedFailureCommand = FALSE;
+
+#ifdef TPM_LIBTPMS_CALLBACKS
+ struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
+
+ if (cbs->tpm_io_init) {
+ ret = cbs->tpm_io_init();
+ if (ret != TPM_SUCCESS)
+ return ret;
+ }
+
+ if (cbs->tpm_nvram_init) {
+ ret = cbs->tpm_nvram_init();
+ if (ret != TPM_SUCCESS)
+ return ret;
+ }
+#endif /* TPM_LIBTPMS_CALLBACKS */
+
+ _rpc__Signal_PowerOff();
+
+ has_cached_state = HasCachedState(TPMLIB_STATE_PERMANENT);
+ has_nvram_file = _TPM2_CheckNVRAMFileExists(&has_nvram_loaddata_callback);
+
+ if (!has_cached_state) {
+ if (!has_nvram_file) {
+ ret = _plat__NVEnable(NULL);
+ if (ret)
+ TPMLIB_LogTPM2Error(
+ "%s: _plat__NVEnable(NULL) failed: %d\n",
+ __func__, ret);
+ if (TPM_Manufacture(TRUE) < 0 || g_inFailureMode) {
+ TPMLIB_LogTPM2Error("%s: TPM_Manufacture(TRUE) failed or TPM in "
+ "failure mode\n", __func__);
+ reportedFailureCommand = TRUE;
+ }
+ }
+ } else if (!has_nvram_loaddata_callback) {
+ ret = _plat__NVEnable_NVChipFile(NULL);
+ if (ret)
+ TPMLIB_LogTPM2Error("%s: _plat__NVEnable_File(NULL) failed: %d\n",
+ __func__, ret);
+ }
+
+ _rpc__Signal_PowerOn(FALSE);
+
+ _rpc__Signal_NvOn();
+
+ if (ret == TPM_SUCCESS) {
+ if (g_inFailureMode)
+ ret = TPM_RC_FAILURE;
+ }
+
+ if (ret == TPM_SUCCESS && has_cached_state) {
+ NvCommit();
+ }
+
+ return ret;
+}
+
+static void TPM2_Terminate(void)
+{
+ TPM_TearDown();
+
+ _rpc__Signal_PowerOff();
+ ExpDCacheFree();
+}
+
+static TPM_RESULT TPM2_Process(unsigned char **respbuffer, uint32_t *resp_size,
+ uint32_t *respbufsize,
+ unsigned char *command, uint32_t command_size)
+{
+ uint8_t locality = 0;
+ _IN_BUFFER req;
+ _OUT_BUFFER resp;
+ unsigned char *tmp;
+
+#ifdef TPM_LIBTPMS_CALLBACKS
+ struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
+
+ if (cbs->tpm_io_getlocality) {
+ TPM_MODIFIER_INDICATOR locty;
+
+ locality = cbs->tpm_io_getlocality(&locty, 0);
+
+ locality = locty;
+ }
+#endif /* TPM_LIBTPMS_CALLBACKS */
+
+ req.BufferSize = command_size;
+ req.Buffer = command;
+
+ /* have the TPM 2 write directly into the response buffer */
+ if (*respbufsize < TPM_BUFFER_MAX || !*respbuffer) {
+ tmp = realloc(*respbuffer, TPM_BUFFER_MAX);
+ if (!tmp) {
+ TPMLIB_LogTPM2Error("Could not allocated %u bytes.\n",
+ TPM_BUFFER_MAX);
+ return TPM_SIZE;
+ }
+ *respbuffer = tmp;
+ *respbufsize = TPM_BUFFER_MAX;
+ }
+ resp.BufferSize = *respbufsize;
+ resp.Buffer = *respbuffer;
+
+ /*
+ * signals for cancellation have to come after we start processing
+ */
+ _rpc__Signal_CancelOff();
+
+ _rpc__Send_Command(locality, req, &resp);
+
+ /* it may come back with a different buffer, especially in failure mode */
+ if (resp.Buffer != *respbuffer) {
+ if (resp.BufferSize > *respbufsize)
+ resp.BufferSize = *respbufsize;
+ memcpy(*respbuffer, resp.Buffer, resp.BufferSize);
+ }
+
+ *resp_size = resp.BufferSize;
+
+ if (g_inFailureMode && !reportedFailureCommand) {
+ reportedFailureCommand = TRUE;
+ TPMLIB_LogTPM2Error("%s: Entered failure mode through command:\n",
+ __func__);
+ TPMLIB_LogArray(~0, command, command_size);
+ }
+
+ return TPM_SUCCESS;
+}
+
+TPM_RESULT TPM2_PersistentAllStore(unsigned char **buf,
+ uint32_t *buflen)
+{
+ BYTE *buffer;
+ INT32 size;
+ unsigned char *nbuffer;
+ TPM_RESULT ret = TPM_SUCCESS;
+ UINT32 written = 0;
+
+ *buflen = NV_MEMORY_SIZE + 32 * 1024;
+ *buf = NULL;
+
+ /* the marshal functions do not indicate insufficient
+ buffer; to make sure we didn't run out of buffer,
+ we check that enough room for the biggest type of
+ chunk (64k) is available and try again. */
+ do {
+ *buflen += 66 * 1024;
+
+ nbuffer = realloc(*buf, *buflen);
+ if (nbuffer == NULL) {
+ free(*buf);
+ *buf = NULL;
+ ret = TPM_SIZE;
+ written = 0;
+ break;
+ }
+
+ *buf = buffer = nbuffer;
+ size = *buflen;
+ written = PERSISTENT_ALL_Marshal(&buffer, &size);
+ } while (size < 66 * 1024);
+
+ *buflen = written;
+
+ return ret;
+}
+
+static TPM_RESULT TPM2_VolatileAllStore(unsigned char **buffer,
+ uint32_t *buflen)
+{
+ TPM_RESULT rc = 0;
+ INT32 size = NV_MEMORY_SIZE;
+ UINT16 written;
+ unsigned char *statebuffer = NULL;
+
+ *buffer = NULL;
+ statebuffer = malloc(size);
+ if (!statebuffer) {
+ TPMLIB_LogTPM2Error("Could not allocate %u bytes.\n", size);
+ return TPM_SIZE;
+ }
+
+ /* statebuffer will change */
+ *buffer = statebuffer;
+
+ written = VolatileSave(&statebuffer, &size);
+ if (written >= size) {
+ free(*buffer);
+ *buffer = NULL;
+ rc = TPM_FAIL;
+ } else {
+ *buflen = written;
+ }
+
+ return rc;
+}
+
+static TPM_RESULT TPM2_CancelCommand(void)
+{
+ _rpc__Signal_CancelOn();
+
+ return TPM_SUCCESS;
+}
+
+static TPM_RESULT TPM2_GetTPMProperty(enum TPMLIB_TPMProperty prop,
+ int *result)
+{
+ switch (prop) {
+ case TPMPROP_TPM_RSA_KEY_LENGTH_MAX:
+ *result = MAX_RSA_KEY_BITS;
+ break;
+
+ case TPMPROP_TPM_KEY_HANDLES:
+ *result = MAX_HANDLE_NUM;
+ break;
+
+ /* not supported for TPM 2 */
+ case TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES:
+ case TPMPROP_TPM_MIN_AUTH_SESSIONS:
+ case TPMPROP_TPM_MIN_TRANS_SESSIONS:
+ case TPMPROP_TPM_MIN_DAA_SESSIONS:
+ case TPMPROP_TPM_MIN_SESSION_LIST:
+ case TPMPROP_TPM_MIN_COUNTERS:
+ case TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN:
+ case TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN:
+ case TPMPROP_TPM_SPACE_SAFETY_MARGIN:
+ case TPMPROP_TPM_MAX_NV_SPACE:
+ case TPMPROP_TPM_MAX_SAVESTATE_SPACE:
+ case TPMPROP_TPM_MAX_VOLATILESTATE_SPACE:
+
+ default:
+ return TPM_FAIL;
+ }
+
+ return TPM_SUCCESS;
+}
+
+/*
+ * TPM2_GetInfo:
+ *
+ * @flags: logical or of flags that query for information
+ *
+ * Return a JSON document with contents queried for by the user's passed flags
+ */
+static char *TPM2_GetInfo(enum TPMLIB_InfoFlags flags)
+{
+ const char *tpmspec =
+ "\"TPMSpecification\":{"
+ "\"family\":\"2.0\","
+ "\"level\":" STRINGIFY(SPEC_LEVEL_NUM) ","
+ "\"revision\":" STRINGIFY(SPEC_VERSION)
+ "}";
+ const char *tpmattrs_temp =
+ "\"TPMAttributes\":{"
+ "\"manufacturer\":\"id:00001014\","
+ "\"version\":\"id:%08X\","
+ "\"model\":\"swtpm\""
+ "}";
+ const char *tpmfeatures_temp =
+ "\"TPMFeatures\":{"
+ "\"RSAKeySizes\":[%s],"
+ "\"CamelliaKeySizes\":[%s]"
+ "}";
+ char *fmt = NULL, *buffer;
+ bool printed = false;
+ char *tpmattrs = NULL;
+ char *tpmfeatures = NULL;
+ char rsakeys[32];
+ char camelliakeys[16];
+ size_t n;
+
+ if (!(buffer = strdup("{%s%s%s}")))
+ return NULL;
+
+ if ((flags & TPMLIB_INFO_TPMSPECIFICATION)) {
+ fmt = buffer;
+ buffer = NULL;
+ if (asprintf(&buffer, fmt, "", tpmspec, "%s%s%s") < 0)
+ goto error;
+ free(fmt);
+ printed = true;
+ }
+
+ if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) {
+ fmt = buffer;
+ buffer = NULL;
+ if (asprintf(&tpmattrs, tpmattrs_temp, FIRMWARE_V1) < 0)
+ goto error;
+ if (asprintf(&buffer, fmt, printed ? "," : "",
+ tpmattrs, "%s%s%s") < 0)
+ goto error;
+ free(fmt);
+ printed = true;
+ }
+
+ if ((flags & TPMLIB_INFO_TPMFEATURES)) {
+ fmt = buffer;
+ buffer = NULL;
+ n = snprintf(rsakeys, sizeof(rsakeys), "%s2048%s%s",
+ RSA_1024 ? "1024," : "",
+ RSA_3072 ? ",3072" : "",
+ RSA_4096 ? ",4096" : "");
+ if (n >= sizeof(rsakeys))
+ goto error;
+ n = snprintf(camelliakeys, sizeof(camelliakeys), "%s%s%s",
+ CAMELLIA_128 ? "128" : "",
+ CAMELLIA_192 ? ",192" : "",
+ CAMELLIA_256 ? ",256" : "");
+ if (n >= sizeof(camelliakeys))
+ goto error;
+ if (asprintf(&tpmfeatures, tpmfeatures_temp,
+ rsakeys, camelliakeys) < 0)
+ goto error;
+ if (asprintf(&buffer, fmt, printed ? "," : "",
+ tpmfeatures, "%s%s%s") < 0)
+ goto error;
+ free(fmt);
+ printed = true;
+ }
+
+ /* nothing else to add */
+ fmt = buffer;
+ buffer = NULL;
+ if (asprintf(&buffer, fmt, "", "", "") < 0)
+ goto error;
+
+ free(fmt);
+ free(tpmattrs);
+ free(tpmfeatures);
+
+ return buffer;
+
+error:
+ free(fmt);
+ free(buffer);
+ free(tpmattrs);
+ free(tpmfeatures);
+
+ return NULL;
+}
+
+static uint32_t tpm2_buffersize = TPM_BUFFER_MAX;
+
+static uint32_t TPM2_SetBufferSize(uint32_t wanted_size,
+ uint32_t *min_size,
+ uint32_t *max_size)
+{
+ const uint32_t min = MAX_CONTEXT_SIZE + 128;
+ const uint32_t max = TPM_BUFFER_MAX;
+
+ if (min_size)
+ *min_size = min;
+ if (max_size)
+ *max_size = max;
+
+ if (wanted_size == 0)
+ return tpm2_buffersize;
+
+ if (wanted_size > max)
+ wanted_size = max;
+ else if (wanted_size < min)
+ wanted_size = min;
+
+ tpm2_buffersize = wanted_size;
+
+ return tpm2_buffersize;
+}
+
+uint32_t TPM2_GetBufferSize(void)
+{
+ return TPM2_SetBufferSize(0, NULL, NULL);
+}
+
+/*
+ * Validate the state blobs to check whether they can be
+ * successfully used by a TPM_INIT.
+*/
+static TPM_RESULT TPM2_ValidateState(enum TPMLIB_StateType st,
+ unsigned int flags)
+{
+ TPM_RESULT ret = TPM_SUCCESS;
+ TPM_RC rc = TPM_RC_SUCCESS;
+ unsigned char *data = NULL;
+ uint32_t length;
+ unsigned char bak_NV[NV_MEMORY_SIZE];
+ INT32 size;
+ BYTE *buffer;
+ BOOL restored;
+
+ /* make backup of current NvChip memory */
+ memcpy(bak_NV, s_NV, sizeof(bak_NV));
+
+#ifdef TPM_LIBTPMS_CALLBACKS
+ struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
+
+ if (cbs->tpm_nvram_init) {
+ ret = cbs->tpm_nvram_init();
+ if (ret != TPM_SUCCESS)
+ return ret;
+ }
+
+#endif
+
+ if ((rc == TPM_RC_SUCCESS) &&
+ (st & (TPMLIB_STATE_PERMANENT | TPMLIB_STATE_SAVE_STATE))) {
+
+#ifdef TPM_LIBTPMS_CALLBACKS
+ if (cbs->tpm_nvram_loaddata) {
+ ret = cbs->tpm_nvram_loaddata(&data, &length, 0,
+ TPM_PERMANENT_ALL_NAME);
+ if (ret != TPM_SUCCESS)
+ return ret;
+ }
+#endif
+
+ if (!data)
+ return TPM_FAIL;
+
+ buffer = data;
+ size = length;
+ rc = PERSISTENT_ALL_Unmarshal(&buffer, &size);
+ free(data);
+ }
+
+ if ((rc == TPM_RC_SUCCESS) &&
+ (st & TPMLIB_STATE_VOLATILE)) {
+ rc = VolatileLoad(&restored);
+ }
+
+ ret = rc;
+
+ return ret;
+}
+
+/*
+ * Get the state blob of the given type. If the TPM is not running, we
+ * get the cached state blobs, if available, otherwise we try to read
+ * it from files. In case the TPM is running, we get it from the running
+ * TPM.
+ */
+static TPM_RESULT TPM2_GetState(enum TPMLIB_StateType st,
+ unsigned char **buffer, uint32_t *buflen)
+{
+ TPM_RESULT ret = TPM_FAIL;
+
+ if (!_rpc__Signal_IsPowerOn()) {
+ struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks();
+ bool is_empty_buffer;
+
+ ret = CopyCachedState(st, buffer, buflen, &is_empty_buffer);
+ if (ret != TPM_SUCCESS || *buffer != NULL || is_empty_buffer)
+ return ret;
+
+ if (cbs->tpm_nvram_init) {
+ ret = cbs->tpm_nvram_init();
+ if (ret != TPM_SUCCESS)
+ return ret;
+
+ /* we can call the TPM 1.2 function here ... */
+ ret = TPM_NVRAM_LoadData(buffer, buflen, 0,
+ TPMLIB_StateTypeToName(st));
+ } else {
+ ret = TPM_FAIL;
+ }
+ return ret;
+ }
+
+ /* from the running TPM */
+ switch (st) {
+ case TPMLIB_STATE_PERMANENT:
+ ret = TPM2_PersistentAllStore(buffer, buflen);
+ break;
+ case TPMLIB_STATE_VOLATILE:
+ ret = TPM2_VolatileAllStore(buffer, buflen);
+ break;
+ case TPMLIB_STATE_SAVE_STATE:
+ *buffer = NULL;
+ *buflen = 0;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Set the state the TPM 2 will use upon next TPM_MainInit(). The TPM 2
+ * must not have been started, yet, or it must have been terminated for this
+ * function to set the state.
+ *
+ * @st: The TPMLIB_StateType describing the type of blob in the buffer
+ * @buffer: pointer to the buffer containing the state blob; NULL pointer clears
+ * previous state
+ * @buflen: length of the buffer
+ */
+static TPM_RESULT TPM2_SetState(enum TPMLIB_StateType st,
+ const unsigned char *buffer, uint32_t buflen)
+{
+ TPM_RESULT ret = TPM_SUCCESS;
+ TPM_RC rc = TPM_RC_SUCCESS;
+ BYTE *stream = NULL, *orig_stream = NULL;
+ INT32 stream_size = buflen;
+ unsigned char *permanent = NULL, *ptr;
+ INT32 permanent_len;
+
+ if (buffer == NULL) {
+ SetCachedState(st, NULL, 0);
+ return TPM_SUCCESS;
+ }
+
+ if (_rpc__Signal_IsPowerOn())
+ return TPM_INVALID_POSTINIT;
+
+ if (ret == TPM_SUCCESS) {
+ stream = malloc(buflen);
+ if (!stream)
+ ret = TPM_SIZE;
+ }
+
+ if (ret == TPM_SUCCESS) {
+ orig_stream = stream;
+ memcpy(stream, buffer, buflen);
+ }
+
+ /* test whether we can accept the blob */
+ if (ret == TPM_SUCCESS) {
+ switch (st) {
+ case TPMLIB_STATE_PERMANENT:
+ rc = PERSISTENT_ALL_Unmarshal(&stream, &stream_size);
+ break;
+ case TPMLIB_STATE_VOLATILE:
+ /* load permanent state first */
+ rc = TPM2_GetState(TPMLIB_STATE_PERMANENT,
+ &permanent, (uint32_t *)&permanent_len);
+ if (rc == TPM_RC_SUCCESS) {
+ ptr = permanent;
+ rc = PERSISTENT_ALL_Unmarshal(&ptr, &permanent_len);
+ if (rc == TPM_RC_SUCCESS)
+ rc = VolatileState_Load(&stream, &stream_size);
+ }
+ break;
+ case TPMLIB_STATE_SAVE_STATE:
+ if (buffer != NULL)
+ rc = TPM_BAD_TYPE;
+ break;
+ }
+ ret = rc;
+ if (ret != TPM_SUCCESS)
+ ClearAllCachedState();
+ }
+
+ /* cache the blob for the TPM_MainInit() to pick it up */
+ if (ret == TPM_SUCCESS) {
+ SetCachedState(st, orig_stream, buflen);
+ } else {
+ free(orig_stream);
+ }
+ free(permanent);
+
+ return ret;
+}
+
+const struct tpm_interface TPM2Interface = {
+ .MainInit = TPM2_MainInit,
+ .Terminate = TPM2_Terminate,
+ .Process = TPM2_Process,
+ .VolatileAllStore = TPM2_VolatileAllStore,
+ .CancelCommand = TPM2_CancelCommand,
+ .GetTPMProperty = TPM2_GetTPMProperty,
+ .GetInfo = TPM2_GetInfo,
+ .TpmEstablishedGet = TPM2_IO_TpmEstablished_Get,
+ .TpmEstablishedReset = TPM2_IO_TpmEstablished_Reset,
+ .HashStart = TPM2_IO_Hash_Start,
+ .HashData = TPM2_IO_Hash_Data,
+ .HashEnd = TPM2_IO_Hash_End,
+ .SetBufferSize = TPM2_SetBufferSize,
+ .ValidateState = TPM2_ValidateState,
+ .SetState = TPM2_SetState,
+ .GetState = TPM2_GetState,
+};