summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_transport.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tpm12/tpm_transport.c2935
1 files changed, 2935 insertions, 0 deletions
diff --git a/src/tpm12/tpm_transport.c b/src/tpm12/tpm_transport.c
new file mode 100644
index 0000000..7b9c520
--- /dev/null
+++ b/src/tpm12/tpm_transport.c
@@ -0,0 +1,2935 @@
+/********************************************************************************/
+/* */
+/* Transport */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: tpm_transport.c 4719 2014-01-15 21:17:47Z kgoldman $ */
+/* */
+/* (c) Copyright IBM Corporation 2006, 2010. */
+/* */
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tpm_audit.h"
+#include "tpm_auth.h"
+#include "tpm_crypto.h"
+#include "tpm_cryptoh.h"
+#include "tpm_debug.h"
+#include "tpm_digest.h"
+#include "tpm_error.h"
+#include "tpm_init.h"
+#include "tpm_key.h"
+#include "tpm_memory.h"
+#include "tpm_nonce.h"
+#include "tpm_process.h"
+#include "tpm_secret.h"
+#include "tpm_ticks.h"
+
+#include "tpm_transport.h"
+
+/* TPM_Transport_CryptMgf1() takes a 'src', a preallocated 'dest', and an MGF1 'pad' of length
+ 'len'.
+
+ 'size is the total length of 'src' and 'dest'.
+ 'index' is the start of the encrypt area
+ 'len' is the length of the encrypt area
+
+ It copies 'src' to 'dest' up to 'index'.
+ It then copies 'src' XOR'ed with 'pad' for 'len'
+ It then copies the remainder of 'src' to 'dest'
+*/
+
+TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest,
+ const unsigned char *src,
+ const unsigned char *pad,
+ uint32_t size,
+ uint32_t index,
+ uint32_t len)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Transport_CryptMgf1: size %u index %u len %u\n", size, index, len);
+ /* sanity check the length */
+ if (rc == 0) {
+ if (index + len > size) {
+ printf("TPM_Transport_CryptMgf1: Error (fatal), bad size\n");
+ rc = TPM_FAIL; /* internal error, should never occur */
+ }
+ }
+ if (rc == 0) {
+ /* leading clear text area */
+ memcpy(dest, src, index);
+ dest += index;
+ src += index;
+ /* encrypt area */
+ TPM_XOR(dest, pad, src, len);
+ dest += len;
+ src += len;
+ /* trailing clear text area */
+ memcpy(dest, src, size - index - len);
+ }
+ return rc;
+}
+
+/* TPM_Transport_CryptSymmetric() takes a 'src', a preallocated 'dest', and a 'symmetric_key'
+ 'pad_in' (CTR or IV) of length 'len'.
+
+ 'size is the total length of 'src' and 'dest'.
+ 'index' is the start of the encrypt area
+ 'len' is the length of the encrypt area
+
+ It copies 'src' to 'dest' up to 'index'.
+ It then encrypts 'src' to 'dest' using 'symmetric_key and 'pad_in' for 'len'
+ It then copies the remainder of 'src' to 'dest'
+*/
+
+TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest,
+ const unsigned char *src,
+ TPM_ALGORITHM_ID algId, /* algorithm */
+ TPM_ENC_SCHEME encScheme, /* mode */
+ const unsigned char *symmetric_key,
+ uint32_t symmetric_key_size,
+ unsigned char *pad_in,
+ uint32_t pad_in_size,
+ uint32_t size,
+ uint32_t index,
+ uint32_t len)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Transport_CryptSymmetric: size %u index %u len %u\n", size, index, len);
+ /* sanity check the length */
+ if (rc == 0) {
+ if (index + len > size) {
+ printf("TPM_Transport_CryptSymmetric: Error (fatal), bad size\n");
+ rc = TPM_FAIL; /* internal error, should never occur */
+ }
+ }
+ if (rc == 0) {
+ /* leading clear text area */
+ memcpy(dest, src, index);
+ dest += index;
+ src += index;
+ /* encrypt area */
+ rc = TPM_SymmetricKeyData_StreamCrypt(dest, /* output */
+ src, /* input */
+ len, /* input */
+ algId, /* algorithm */
+ encScheme, /* mode */
+ symmetric_key, /* input */
+ symmetric_key_size, /* input */
+ pad_in, /* input */
+ pad_in_size); /* input */
+ }
+ if (rc == 0) {
+ dest += len;
+ src += len;
+ /* trailing clear text area */
+ memcpy(dest, src, size - index - len);
+ }
+ return rc;
+}
+
+/*
+ Transport Sessions (the entire array)
+*/
+
+void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ size_t i;
+
+ printf(" TPM_TransportSessions_Init:\n");
+ for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) {
+ TPM_TransportInternal_Init(&(transSessions[i]));
+ }
+ return;
+}
+
+/* TPM_TransportSessions_Load() reads a count of the number of stored sessions and then loads those
+ sessions.
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_TransportSessions_Init()
+ After use, call TPM_TransportSessions_Delete() to free memory
+*/
+
+TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ uint32_t activeCount;
+
+ printf(" TPM_TransportSessions_Load:\n");
+ /* load active count */
+ if (rc == 0) {
+ rc = TPM_Load32(&activeCount, stream, stream_size);
+ }
+ if (rc == 0) {
+ if (activeCount > TPM_MIN_TRANS_SESSIONS) {
+ printf("TPM_TransportSessions_Load: Error (fatal) %u sessions, %u slots\n",
+ activeCount, TPM_MIN_TRANS_SESSIONS);
+ rc = TPM_FAIL;
+ }
+ }
+ if (rc == 0) {
+ printf(" TPM_TransportSessions_Load: Loading %u sessions\n", activeCount);
+ }
+ for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) {
+ rc = TPM_TransportInternal_Load(&(transSessions[i]), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_Store() stores a count of the active sessions, followed by the sessions.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer,
+ TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ uint32_t space; /* free transport session slots */
+ uint32_t activeCount; /* used transport session slots */
+
+ /* store active count */
+ if (rc == 0) {
+ TPM_TransportSessions_GetSpace(&space, transSessions);
+ activeCount = TPM_MIN_TRANS_SESSIONS - space;
+ printf(" TPM_TransSessions_Store: Storing %u sessions\n", activeCount);
+ rc = TPM_Sbuffer_Append32(sbuffer, activeCount);
+ }
+ /* store transport sessions */
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) {
+ if ((transSessions[i]).valid) { /* if the session is active */
+ rc = TPM_TransportInternal_Store(sbuffer, &(transSessions[i]));
+ }
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_Delete() terminates all sessions
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportSessions_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ size_t i;
+
+ printf(" TPM_TransportSessions_Delete:\n");
+ for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) {
+ TPM_TransportInternal_Delete(&(transSessions[i]));
+ }
+ return;
+}
+
+/* TPM_TransportSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not.
+
+ If TRUE, 'index' holds the first free position.
+*/
+
+void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index,
+ TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ printf(" TPM_TransportSessions_IsSpace:\n");
+ for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_TRANS_SESSIONS ; (*index)++) {
+ if (!((transSessions[*index]).valid)) {
+ printf(" TPM_TransportSessions_IsSpace: Found space at %u\n", *index);
+ *isSpace = TRUE;
+ break;
+ }
+ }
+ return;
+}
+
+/* TPM_TransportSessions_GetSpace() returns the number of unused transport sessions.
+
+*/
+
+void TPM_TransportSessions_GetSpace(uint32_t *space,
+ TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ uint32_t i;
+
+ printf(" TPM_TransportSessions_GetSpace:\n");
+ for (*space = 0 , i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) {
+ if (!((transSessions[i]).valid)) {
+ (*space)++;
+ }
+ }
+ return;
+}
+
+/* TPM_TransportSessions_StoreHandles() stores
+
+ - the number of loaded sessions
+ - a list of session handles
+*/
+
+TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer,
+ TPM_TRANSPORT_INTERNAL *transSessions)
+{
+ TPM_RESULT rc = 0;
+ uint16_t i;
+ uint32_t space;
+
+ printf(" TPM_TransportSessions_StoreHandles:\n");
+ /* get the number of loaded handles */
+ if (rc == 0) {
+ TPM_TransportSessions_GetSpace(&space, transSessions);
+ /* store loaded handle count. Cast safe because of TPM_MIN_TRANS_SESSIONS value */
+ printf(" TPM_TransportSessions_StoreHandles: %u handles\n",
+ TPM_MIN_TRANS_SESSIONS - space);
+ rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_TRANS_SESSIONS - space));
+ }
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) {
+ if ((transSessions[i]).valid) { /* if the index is loaded */
+ rc = TPM_Sbuffer_Append32(sbuffer, (transSessions[i]).transHandle); /* store it */
+ }
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_GetNewHandle() checks for space in the transport sessions table.
+
+ If there is space, it returns a TPM_TRANSPORT_INTERNAL entry in 'tpm_transport_internal'. The
+ entry is marked 'valid'.
+
+ Returns TPM_RESOURCES if there is no space in the transport sessions table.
+*/
+
+TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal,
+ TPM_TRANSPORT_INTERNAL *transportSessions)
+{
+ TPM_RESULT rc = 0;
+ uint32_t index;
+ TPM_BOOL isSpace;
+ TPM_TRANSHANDLE transportHandle = 0; /* no suggested value */
+
+ printf(" TPM_TransportSessions_GetNewHandle:\n");
+ /* is there an empty entry, get the location index */
+ if (rc == 0) {
+ TPM_TransportSessions_IsSpace(&isSpace, &index, transportSessions);
+ if (!isSpace) {
+ printf("TPM_TransportSessions_GetNewHandle: Error, "
+ "no space in TransportSessions table\n");
+ rc = TPM_RESOURCES;
+ }
+ }
+ /* assign transport handle */
+ if (rc == 0) {
+ rc = TPM_Handle_GenerateHandle(&transportHandle, /* I/O */
+ transportSessions, /* handle array */
+ FALSE, /* keepHandle */
+ FALSE, /* isKeyHandle */
+ (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry);
+ }
+ if (rc == 0) {
+ printf(" TPM_TransportSessions_GetNewHandle: Assigned handle %08x\n", transportHandle);
+ /* return the TPM_TRANSPORT_INTERNAL */
+ *tpm_transport_internal = &(transportSessions[index]);
+ /* assign the handle */
+ (*tpm_transport_internal)->transHandle = transportHandle;
+ (*tpm_transport_internal)->valid = TRUE;
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_GetEntry() searches all 'transportSessions' entries for the entry matching
+ the handle, and returns the TPM_TRANSPORT_INTERNAL entry associated with the handle.
+
+ Returns
+ 0 for success
+ TPM_INVALID_AUTHHANDLE if the handle is not found
+*/
+
+TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal,
+ TPM_TRANSPORT_INTERNAL *transportSessions, /* array */
+ TPM_TRANSHANDLE transportHandle) /* input */
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ TPM_BOOL found;
+
+ printf(" TPM_TransportSessions_GetEntry: transportHandle %08x\n", transportHandle);
+ for (i = 0, found = FALSE ; (i < TPM_MIN_TRANS_SESSIONS) && !found ; i++) {
+ if ((transportSessions[i].valid) &&
+ (transportSessions[i].transHandle == transportHandle)) { /* found */
+ found = TRUE;
+ *tpm_transport_internal = &(transportSessions[i]);
+ }
+ }
+ if (!found) {
+ printf(" TPM_TransportSessions_GetEntry: transport session handle %08x not found\n",
+ transportHandle);
+ rc = TPM_INVALID_AUTHHANDLE;
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_AddEntry() adds an TPM_TRANSPORT_INTERNAL object to the list.
+
+ If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not
+ currently in use.
+
+ The handle is returned in tpm_handle.
+*/
+
+TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */
+ TPM_BOOL keepHandle, /* input */
+ TPM_TRANSPORT_INTERNAL *transSessions, /* input */
+ TPM_TRANSPORT_INTERNAL *tpm_transport_internal) /* in */
+{
+ TPM_RESULT rc = 0;
+ uint32_t index;
+ TPM_BOOL isSpace;
+
+ printf(" TPM_TransportSessions_AddEntry: handle %08x, keepHandle %u\n",
+ *tpm_handle, keepHandle);
+ /* check for valid TPM_TRANSPORT_INTERNAL */
+ if (rc == 0) {
+ if (tpm_transport_internal == NULL) { /* NOTE: should never occur */
+ printf("TPM_TransportSessions_AddEntry: Error (fatal), NULL TPM_TRANSPORT_INTERNAL\n");
+ rc = TPM_FAIL;
+ }
+ }
+ /* is there an empty entry, get the location index */
+ if (rc == 0) {
+ TPM_TransportSessions_IsSpace(&isSpace, &index, transSessions);
+ if (!isSpace) {
+ printf("TPM_TransportSessions_AddEntry: Error, transport session entries full\n");
+ rc = TPM_RESOURCES;
+ }
+ }
+ if (rc == 0) {
+ rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */
+ transSessions, /* handle array */
+ keepHandle, /* keepHandle */
+ FALSE, /* isKeyHandle */
+ (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry);
+ }
+ if (rc == 0) {
+ tpm_transport_internal->transHandle = *tpm_handle;
+ tpm_transport_internal->valid = TRUE;
+ TPM_TransportInternal_Copy(&(transSessions[index]), tpm_transport_internal);
+ printf(" TPM_TransportSessions_AddEntry: Index %u handle %08x\n",
+ index, transSessions[index].transHandle);
+ }
+ return rc;
+}
+
+/* TPM_TransportSessions_TerminateHandle() terminates the session associated with
+ 'transporthHandle'.
+
+ If the session is exclusive (indicated by a match with TPM_STANY_FLAGS -> transportExclusive),
+ clear that flag.
+*/
+
+TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *transportSessions,
+ TPM_TRANSHANDLE transportHandle,
+ TPM_TRANSHANDLE *transportExclusive)
+{
+ TPM_RESULT rc = 0;
+ TPM_TRANSPORT_INTERNAL *tpm_transport_internal;
+
+ printf(" TPM_TransportSessions_TerminateHandle: Handle %08x\n", transportHandle);
+ /* get the TPM_TRANSPORT_INTERNAL associated with the TPM_TRANSHANDLE */
+ if (rc == 0) {
+ rc = TPM_TransportSessions_GetEntry(&tpm_transport_internal,
+ transportSessions,
+ transportHandle);
+ }
+ /* if the session being terminated is exclusive, reset the flag */
+ if (rc == 0) {
+ if (transportHandle == *transportExclusive) {
+ printf(" TPM_TransportSessions_TerminateHandle: Is exclusive transport session\n");
+ if (!(tpm_transport_internal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE)) {
+ printf("TPM_TransportSessions_TerminateHandle: Error (fatal), "
+ "attribute is not exclusive\n");
+ rc = TPM_FAIL; /* internal error, should not occur */
+ }
+ *transportExclusive = 0;
+ }
+ }
+ /* invalidate the valid handle */
+ if (rc == 0) {
+ TPM_TransportInternal_Delete(tpm_transport_internal);
+ }
+ return rc;
+}
+
+/*
+ TPM_TRANSPORT_PUBLIC
+*/
+
+/* TPM_TransportPublic_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public)
+{
+ printf(" TPM_TransportPublic_Init:\n");
+ tpm_transport_public->transAttributes = 0;
+ tpm_transport_public->algId = 0;
+ tpm_transport_public->encScheme = TPM_ES_NONE;
+ return;
+}
+
+/* TPM_TransportPublic_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_TransportPublic_Init()
+ After use, call TPM_TransportPublic_Delete() to free memory
+*/
+
+TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportPublic_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_TRANSPORT_PUBLIC, stream, stream_size);
+ }
+ /* load transAttributes */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_transport_public->transAttributes ), stream, stream_size);
+ }
+ /* load algId */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_transport_public->algId), stream, stream_size);
+ }
+ /* load encScheme */
+ if (rc == 0) {
+ rc = TPM_Load16(&(tpm_transport_public->encScheme), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_TransportPublic_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_TRANSPORT_PUBLIC *tpm_transport_public)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportPublic_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_PUBLIC);
+ }
+ /* store transAttributes */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->transAttributes);
+ }
+ /* store algId */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->algId);
+ }
+ /* store encScheme */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_transport_public->encScheme);
+ }
+ return rc;
+}
+
+/* TPM_TransportPublic_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportPublic_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public)
+{
+ printf(" TPM_TransportPublic_Delete:\n");
+ if (tpm_transport_public != NULL) {
+ TPM_TransportPublic_Init(tpm_transport_public);
+ }
+ return;
+}
+
+/* TPM_TransportPublic_Copy() copies the 'src' to the 'dest' structure
+
+*/
+
+TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest,
+ const TPM_TRANSPORT_PUBLIC *src)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportPublic_Copy:\n");
+ /* copy transAttributes */
+ dest->transAttributes = src->transAttributes;
+ /* copy algId */
+ dest->algId = src->algId;
+ /* copy encScheme */
+ dest->encScheme = src->encScheme;
+ return rc;
+}
+
+/* TPM_TransportPublic_CheckAlgId() returns 'supported' TRUE if the transport encryption algorithm
+ is supported by the TPM
+
+*/
+
+void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported,
+ TPM_ALGORITHM_ID algId)
+{
+ printf(" TPM_TransportPublic_CheckAlgId: %08x\n", algId);
+ switch (algId) {
+ /* supported protocols */
+ case TPM_ALG_MGF1:
+ case TPM_ALG_AES128:
+ *supported = TRUE;
+ break;
+ /* unsupported protocols */
+ case TPM_ALG_RSA:
+ case TPM_ALG_SHA:
+ case TPM_ALG_HMAC:
+ case TPM_ALG_AES192:
+ case TPM_ALG_AES256:
+ default:
+ *supported = FALSE;
+ break;
+ }
+ return;
+}
+
+/* TPM_TransportPublic_CheckEncScheme() returns success and the blockSize if the transport algId and
+ encScheme are supported by the TPM.
+*/
+
+TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize,
+ TPM_ALGORITHM_ID algId,
+ TPM_ENC_SCHEME encScheme,
+ TPM_BOOL FIPS)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportPublic_CheckEncScheme: algId %08x encScheme %04hx\n", algId, encScheme);
+ switch (algId) {
+ /* supported protocols with no encScheme */
+ case TPM_ALG_MGF1:
+ *blockSize = 0; /* MGF1 does not use blocks */
+ if (FIPS) {
+ printf("TPM_TransportPublic_CheckEncScheme: Error, "
+ "TPM_ALG_MGF1 not supported in FIPS\n");
+ rc = TPM_INAPPROPRIATE_ENC;
+ }
+ /* For TPM_ALG_MGF1, TPM_ENC_SCHEME is not used. The TPM MAY validate that TPM_ENC_SCHEME
+ is TPM_ES_NONE. */
+ if (encScheme != TPM_ES_NONE) {
+ printf("TPM_TransportPublic_CheckEncScheme: Error, "
+ "TPM_ALG_MGF1 must use TPM_ES_NONE\n");
+ rc = TPM_INAPPROPRIATE_ENC;
+ }
+ break;
+ /* protocols with encScheme */
+ case TPM_ALG_AES128:
+ switch(encScheme) {
+ case TPM_ES_SYM_CTR: /* CTR mode */
+ case TPM_ES_SYM_OFB: /* OFB mode */
+ *blockSize = 128/8;
+ break;
+ default:
+ printf("TPM_TransportPublic_CheckEncScheme: Error, AES128 encScheme not supported\n");
+ rc = TPM_INAPPROPRIATE_ENC;
+ break;
+ }
+ break;
+ /* unsupported protocols */
+ case TPM_ALG_AES192:
+ case TPM_ALG_AES256:
+ case TPM_ALG_RSA:
+ case TPM_ALG_SHA:
+ case TPM_ALG_HMAC:
+ case TPM_ALG_XOR:
+ default:
+ printf("TPM_TransportPublic_CheckEncScheme: Error, algId not supported\n");
+ rc = TPM_BAD_KEY_PROPERTY;
+ break;
+ }
+ return rc;
+}
+
+/*
+ TPM_TRANSPORT_INTERNAL
+*/
+
+/* TPM_TransportInternal_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal)
+{
+ printf(" TPM_TransportInternal_Init:\n");
+ TPM_Secret_Init(tpm_transport_internal->authData);
+ TPM_TransportPublic_Init(&(tpm_transport_internal->transPublic));
+ tpm_transport_internal->transHandle = 0;
+ TPM_Nonce_Init(tpm_transport_internal->transNonceEven);
+ TPM_Digest_Init(tpm_transport_internal->transDigest);
+ tpm_transport_internal->valid = FALSE;
+ return;
+}
+
+/* TPM_TransportInternal_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_TransportInternal_Init()
+ After use, call TPM_TransportInternal_Delete() to free memory
+*/
+
+TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportInternal_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_TRANSPORT_INTERNAL, stream, stream_size);
+ }
+ /* load authData */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_transport_internal->authData, stream, stream_size);
+ }
+ /* load transPublic */
+ if (rc == 0) {
+ rc = TPM_TransportPublic_Load(&(tpm_transport_internal->transPublic), stream, stream_size);
+ }
+ /* load transHandle */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_transport_internal->transHandle), stream, stream_size);
+ }
+ /* load transNonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_transport_internal->transNonceEven, stream, stream_size);
+ }
+ /* load transDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_transport_internal->transDigest, stream, stream_size);
+ }
+ /* load valid */
+ if (rc == 0) {
+ tpm_transport_internal->valid = TRUE;
+ }
+ return rc;
+}
+
+/* TPM_TransportInternal_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_TRANSPORT_INTERNAL *tpm_transport_internal)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportInternal_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_INTERNAL);
+ }
+ /* store authData */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_transport_internal->authData);
+ }
+ /* store transPublic */
+ if (rc == 0) {
+ rc = TPM_TransportPublic_Store(sbuffer, &(tpm_transport_internal->transPublic));
+ }
+ /* store transHandle */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_internal->transHandle);
+ }
+ /* store transNonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(sbuffer, tpm_transport_internal->transNonceEven);
+ }
+ /* store transDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_transport_internal->transDigest);
+ }
+ return rc;
+}
+
+/* TPM_TransportInternal_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportInternal_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal)
+{
+ printf(" TPM_TransportInternal_Delete:\n");
+ if (tpm_transport_internal != NULL) {
+ TPM_TransportPublic_Delete(&(tpm_transport_internal->transPublic));
+ TPM_TransportInternal_Init(tpm_transport_internal);
+ }
+ return;
+}
+
+/* TPM_TransportInternal_Copy() copies the source to the destination.
+
+*/
+
+void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal,
+ TPM_TRANSPORT_INTERNAL *src_transport_internal)
+{
+ TPM_Secret_Copy(dest_transport_internal->authData, src_transport_internal->authData);
+ TPM_TransportPublic_Copy(&(dest_transport_internal->transPublic),
+ &(src_transport_internal->transPublic));
+ dest_transport_internal->transHandle = src_transport_internal->transHandle;
+ TPM_Nonce_Copy(dest_transport_internal->transNonceEven, src_transport_internal->transNonceEven);
+ TPM_Digest_Copy(dest_transport_internal->transDigest, src_transport_internal->transDigest);
+ dest_transport_internal->valid = src_transport_internal->valid;
+}
+
+/* TPM_TransportInternal_Check() checks the authorization of a command.
+
+ There is no need to protect against dictionary attacks. The first failure terminates the
+ transport session.
+
+ Returns TPM_AUTH2FAIL if the TPM_AUTHDATA does not match.
+*/
+
+TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, /* digest of inputs
+ above line */
+ TPM_TRANSPORT_INTERNAL *tpm_transport_internal,
+ TPM_NONCE transNonceOdd, /* Nonce generated
+ by system
+ associated with
+ transHandle */
+ TPM_BOOL continueTransSession,
+ TPM_AUTHDATA transAuth) /* Authorization
+ digest for
+ input */
+{
+ TPM_RESULT rc = 0;
+ TPM_BOOL valid;
+
+ printf(" TPM_TransportInternal_Check:\n");
+ if (rc == 0) {
+ TPM_PrintFour(" TPM_TransportInternal_Check: inParamDigest", inParamDigest);
+ TPM_PrintFour(" TPM_TransportInternal_Check: usageAuth (key)",
+ tpm_transport_internal->authData);
+ TPM_PrintFour(" TPM_TransportInternal_Check: nonceEven",
+ tpm_transport_internal->transNonceEven);
+ TPM_PrintFour(" TPM_TransportInternal_Check: nonceOdd", transNonceOdd);
+ printf (" TPM_TransportInternal_Check: continueSession %02x\n", continueTransSession);
+ /* HMAC the inParamDigest, transLastNonceEven, transNonceOdd, continueTransSession */
+ /* transLastNonceEven is retrieved from internal transport session storage */
+ rc = TPM_HMAC_Check(&valid,
+ transAuth, /* expected, from command */
+ tpm_transport_internal->authData, /* key */
+ sizeof(TPM_DIGEST), inParamDigest, /* command digest */
+ sizeof(TPM_NONCE), tpm_transport_internal->transNonceEven, /* 2H */
+ sizeof(TPM_NONCE), transNonceOdd, /* 3H */
+ sizeof(TPM_BOOL), &continueTransSession, /* 4H */
+ 0, NULL);
+ }
+ if (rc == 0) {
+ if (!valid) {
+ printf("TPM_TransportInternal_Check: Error, authorization failed\n");
+ rc = TPM_AUTH2FAIL;
+ }
+ }
+ return rc;
+}
+
+/* TPM_TransportInternal_Set() sets the transport response transAuth.
+
+ It conditionally generates the next transNonceEven.
+
+ It appends transNonceEven and continueTransSession to the response.
+
+ It generates transAuth using outParamDigest and the standard 'below the line' HMAC rules and
+ appends it to the response.
+*/
+
+TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response,
+ TPM_TRANSPORT_INTERNAL *tpm_transport_internal,
+ TPM_DIGEST outParamDigest,
+ TPM_NONCE transNonceOdd,
+ TPM_BOOL continueTransSession,
+ TPM_BOOL generateNonceEven)
+{
+ TPM_RESULT rc = 0;
+ TPM_AUTHDATA transAuth; /* The authorization digest for the returned parameters */
+
+ printf(" TPM_TransportInternal_Set:\n");
+ /* generate transNonceEven if not already done by caller */
+ if ((rc == 0) && generateNonceEven) {
+ rc = TPM_Nonce_Generate(tpm_transport_internal->transNonceEven);
+ }
+ /* append transNonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(response, tpm_transport_internal->transNonceEven);
+ }
+ /* append continueTransSession*/
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(response, &continueTransSession, sizeof(TPM_BOOL));
+ }
+ /* Calculate transAuth using the transport session authData */
+ if (rc == 0) {
+ rc = TPM_Authdata_Generate(transAuth, /* result */
+ tpm_transport_internal->authData, /* HMAC key */
+ outParamDigest, /* params */
+ tpm_transport_internal->transNonceEven,
+ transNonceOdd,
+ continueTransSession);
+ }
+ /* append transAuth */
+ if (rc == 0) {
+ rc = TPM_Authdata_Store(response, transAuth);
+ }
+ return rc;
+}
+
+/*
+ TPM_TRANSPORT_LOG_IN
+*/
+
+/* TPM_TransportLogIn_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in)
+{
+ printf(" TPM_TransportLogIn_Init:\n");
+ TPM_Digest_Init(tpm_transport_log_in->parameters);
+ TPM_Digest_Init(tpm_transport_log_in->pubKeyHash);
+ return;
+}
+
+/* TPM_TransportLogIn_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportLogIn_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_IN);
+ }
+ /* store parameters */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->parameters);
+ }
+ /* store pubKeyHash */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->pubKeyHash);
+ }
+ return rc;
+}
+
+/* TPM_TransportLogIn_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportLogIn_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in)
+{
+ printf(" TPM_TransportLogIn_Delete:\n");
+ if (tpm_transport_log_in != NULL) {
+ TPM_TransportLogIn_Init(tpm_transport_log_in);
+ }
+ return;
+}
+
+/* TPM_TransportLogIn_Extend() extends 'tpm_digest'
+
+ tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_in)
+*/
+
+TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest,
+ TPM_TRANSPORT_LOG_IN *tpm_transport_log_in)
+{
+ TPM_RESULT rc = 0;
+ TPM_STORE_BUFFER sbuffer;
+ const unsigned char *buffer; /* serialized buffer */
+ uint32_t length; /* serialization length */
+
+ printf(" TPM_TransportLogIn_Extend:\n");
+ TPM_Sbuffer_Init(&sbuffer); /* freed @1 */
+ /* serialize TPM_TRANSPORT_LOG_IN */
+ if (rc == 0) {
+ rc = TPM_TransportLogIn_Store(&sbuffer, tpm_transport_log_in);
+ }
+ if (rc == 0) {
+ /* get the TPM_TRANSPORT_LOG_IN serialization results */
+ TPM_Sbuffer_Get(&sbuffer, &buffer, &length);
+ TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE);
+ TPM_PrintAll(" TPM_TransportLogIn_Extend", buffer, length);
+ rc = TPM_SHA1(tpm_digest,
+ TPM_DIGEST_SIZE, tpm_digest,
+ length, buffer,
+ 0, NULL);
+ TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE);
+ }
+ TPM_Sbuffer_Delete(&sbuffer); /* @1 */
+ return rc;
+}
+
+/*
+ TPM_TRANSPORT_LOG_OUT
+*/
+
+/* TPM_TransportLogOut_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out)
+{
+ printf(" TPM_TransportLogOut_Init:\n");
+ TPM_CurrentTicks_Init(&(tpm_transport_log_out->currentTicks));
+ TPM_Digest_Init(tpm_transport_log_out->parameters);
+ tpm_transport_log_out = 0;
+ return;
+}
+
+/* TPM_TransportLogOut_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportLogOut_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_OUT);
+ }
+ /* store currentTicks */
+ if (rc == 0) {
+ rc = TPM_CurrentTicks_Store(sbuffer, &(tpm_transport_log_out->currentTicks));
+ }
+ /* store parameters */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_transport_log_out->parameters);
+ }
+ /* store locality */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_log_out->locality);
+ }
+ return rc;
+}
+
+/* TPM_TransportLogOut_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportLogOut_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out)
+{
+ printf(" TPM_TransportLogOut_Delete:\n");
+ if (tpm_transport_log_out != NULL) {
+ TPM_TransportLogOut_Init(tpm_transport_log_out);
+ }
+ return;
+}
+
+/* TPM_TransportLogOut_Extend() extends 'tpm_digest'
+
+ tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_out)
+*/
+
+TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest,
+ TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out)
+{
+ TPM_RESULT rc = 0;
+ TPM_STORE_BUFFER sbuffer;
+ const unsigned char *buffer; /* serialized buffer */
+ uint32_t length; /* serialization length */
+
+ printf(" TPM_TransportLogOut_Extend:\n");
+ TPM_Sbuffer_Init(&sbuffer); /* freed @1 */
+ /* serialize TPM_TRANSPORT_LOG_OUT */
+ if (rc == 0) {
+ rc = TPM_TransportLogOut_Store(&sbuffer, tpm_transport_log_out);
+ }
+ if (rc == 0) {
+ /* get the TPM_TRANSPORT_LOG_OUT serialization results */
+ TPM_Sbuffer_Get(&sbuffer, &buffer, &length);
+ TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE);
+ TPM_PrintAll(" TPM_TransportLogOut_Extend:", buffer, length);
+ rc = TPM_SHA1(tpm_digest,
+ TPM_DIGEST_SIZE, tpm_digest,
+ length, buffer,
+ 0, NULL);
+ TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE);
+ }
+ TPM_Sbuffer_Delete(&sbuffer); /* @1 */
+ return rc;
+}
+
+/*
+ TPM_TRANSPORT_AUTH
+*/
+
+/* TPM_TransportAuth_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth)
+{
+ printf(" TPM_TransportAuth_Init:\n");
+ TPM_Secret_Init(tpm_transport_auth->authData);
+ return;
+}
+
+/* TPM_TransportAuth_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_TransportAuth_Init()
+ After use, call TPM_TransportAuth_Delete() to free memory
+*/
+
+TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportAuth_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_TRANSPORT_AUTH, stream, stream_size);
+ }
+ /* load authData */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_transport_auth->authData, stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_TransportAuth_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_TRANSPORT_AUTH *tpm_transport_auth)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_TransportAuth_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_AUTH);
+ }
+ /* store authData */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_transport_auth->authData);
+ }
+ return rc;
+}
+
+/* TPM_TransportAuth_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_TransportAuth_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth)
+{
+ printf(" TPM_TransportAuth_Delete:\n");
+ if (tpm_transport_auth != NULL) {
+ TPM_TransportAuth_Init(tpm_transport_auth);
+ }
+ return;
+}
+
+/* TPM_TransportAuth_DecryptSecret() decrypts the secret using the private key. The
+ result is deserialized and stored in the TPM_TRANSPORT_AUTH structure.
+*/
+
+TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, /* result */
+ TPM_SIZED_BUFFER *secret, /* encrypted input */
+ TPM_KEY *tpm_key) /* key for decrypting */
+{
+ TPM_RESULT rc = 0;
+ unsigned char *decryptData = NULL; /* freed @1 */
+ uint32_t decryptDataLength = 0; /* actual valid data */
+ unsigned char *stream;
+ uint32_t stream_size;
+
+ printf(" TPM_TransportAuth_DecryptSecret:\n");
+ /* allocate space for the decrypted data */
+ if (rc == 0) {
+ rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */
+ &decryptDataLength, /* actual size of decrypted data */
+ secret->buffer, /* encrypted data */
+ secret->size, /* encrypted data size */
+ tpm_key);
+ }
+ /* load the TPM_TRANSPORT_AUTH structure from the decrypted data stream */
+ if (rc == 0) {
+ /* use temporary variables, because TPM_TransportAuth_Load() moves the stream */
+ stream = decryptData;
+ stream_size = decryptDataLength;
+ rc = TPM_TransportAuth_Load(tpm_transport_auth, &stream, &stream_size);
+ }
+ free(decryptData); /* @1 */
+ return rc;
+}
+
+/*
+ Processing Functions
+*/
+
+/* 24.1 TPM_EstablishTransport rev 98
+
+ This establishes the transport session. Depending on the attributes specified for the session
+ this may establish shared secrets, encryption keys, and session logs. The session will be in use
+ for by the TPM_ExecuteTransport command.
+
+ The only restriction on what can happen inside of a transport session is that there is no
+ "nesting" of sessions. It is permissible to perform operations that delete internal state and
+ make the TPM inoperable.
+*/
+
+TPM_RESULT TPM_Process_EstablishTransport(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE encHandle; /* The handle to the key that encrypted the blob */
+ TPM_TRANSPORT_PUBLIC transPublic; /* The public information describing the transport
+ session */
+ TPM_SIZED_BUFFER secret; /* The encrypted secret area */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for
+ keyHandle authorization */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: encKey.usageAuth */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY *encKey = NULL; /* the key specified by encHandle */
+ TPM_BOOL parentPCRStatus;
+ TPM_SECRET *encKeyUsageAuth;
+ TPM_AUTHDATA *a1AuthData = NULL;
+ TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal;
+ TPM_TRANSPORT_AUTH k1TransportAuth;
+ uint32_t blockSize; /* symmetric key block size, not used */
+ TPM_TRANSPORT_LOG_IN l1TransportLogIn;
+ TPM_TRANSPORT_LOG_OUT l2TransportLogOut;
+ TPM_STORE_BUFFER transPublicSbuffer; /* serialized transPublic */
+ const unsigned char *transPublicBuffer; /* serialized buffer */
+ uint32_t transPublicLength; /* serialization length */
+ TPM_STORE_BUFFER currentTicksSbuffer; /* serialized currentTicks */
+ const unsigned char *currentTicksBuffer; /* serialized buffer */
+ uint32_t currentTicksLength; /* serialization length */
+ TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */
+ uint32_t nSecretSize; /* secretSize in nbo */
+ TPM_RESULT nReturnCode; /* returnCode in nbo */
+ TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */
+ TPM_BOOL trans_session_added = FALSE;
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_CURRENT_TICKS currentTicks; /* The current tick count */
+ TPM_NONCE transNonceEven; /* The even nonce in use for subsequent
+ execute transport */
+
+ printf("TPM_Process_EstablishTransport: Ordinal Entry\n");
+ TPM_TransportPublic_Init(&transPublic); /* freed @1 */
+ TPM_SizedBuffer_Init(&secret); /* freed @2 */
+ TPM_CurrentTicks_Init(&currentTicks); /* no need to free */
+ TPM_TransportAuth_Init(&k1TransportAuth); /* freed @4 */
+ TPM_TransportLogIn_Init(&l1TransportLogIn); /* freed @5 */
+ TPM_TransportLogOut_Init(&l2TransportLogOut); /* freed @6 */
+ TPM_Sbuffer_Init(&transPublicSbuffer); /* freed @7 */
+ TPM_Sbuffer_Init(&currentTicksSbuffer); /* freed @8 */
+ /*
+ get inputs
+ */
+ /* get encHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&encHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get transPublic */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_EstablishTransport: keyHandle %08x\n", encHandle);
+ returnCode = TPM_TransportPublic_Load(&transPublic, &command, &paramSize);
+ }
+ /* get secret */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_EstablishTransport: transPublic->transAttributes %08x\n",
+ transPublic.transAttributes);
+ returnCode = TPM_SizedBuffer_Load(&secret, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ keyAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_EstablishTransport: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ if (returnCode == TPM_SUCCESS) {
+ /* 1. If encHandle is TPM_KH_TRANSPORT then */
+ if (encHandle == TPM_KH_TRANSPORT) {
+ printf("TPM_Process_EstablishTransport: TPM_KH_TRANSPORT clear text secret\n");
+ /* a. If tag is NOT TPM_TAG_RQU_COMMAND return TPM_BADTAG */
+ if (returnCode == TPM_SUCCESS) {
+ if (tag != TPM_TAG_RQU_COMMAND) {
+ printf("TPM_Process_EstablishTransport: Error, "
+ "TPM_KH_TRANSPORT but not auth-0\n");
+ returnCode = TPM_BADTAG;
+ }
+ }
+ /* b. If transPublic -> transAttributes specifies TPM_TRANSPORT_ENCRYPT return
+ TPM_BAD_SCHEME */
+ if (returnCode == TPM_SUCCESS) {
+ if (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) {
+ printf("TPM_Process_EstablishTransport: Error, "
+ "TPM_KH_TRANSPORT but TPM_TRANSPORT_ENCRYPT\n");
+ returnCode = TPM_BAD_SCHEME;
+ }
+ }
+ /* c. If secretSize is not 20 return TPM_BAD_PARAM_SIZE */
+ if (returnCode == TPM_SUCCESS) {
+ if (secret.size != TPM_DIGEST_SIZE) {
+ printf("TPM_Process_EstablishTransport: Error, secretSize %u not %u\n",
+ secret.size, TPM_DIGEST_SIZE);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* d. Set A1 to secret */
+ if (returnCode == TPM_SUCCESS) {
+ a1AuthData = (TPM_AUTHDATA *)(secret.buffer);
+ TPM_PrintFour("TPM_Process_EstablishTransport: transport clear text authData", *a1AuthData);
+ }
+ }
+ /* 2. Else */
+ else {
+ printf("TPM_Process_EstablishTransport: Decrypt secret\n");
+ /* get the key corresponding to the encHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&encKey, &parentPCRStatus, tpm_state,
+ encHandle,
+ FALSE, /* not r/o, using to encrypt */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ /* a. encHandle -> keyUsage MUST be TPM_KEY_STORAGE or TPM_KEY_LEGACY return
+ TPM_INVALID_KEYUSAGE on error */
+ if (returnCode == TPM_SUCCESS) {
+ if ((encKey->keyUsage != TPM_KEY_STORAGE) &&
+ (encKey->keyUsage != TPM_KEY_LEGACY)) {
+ printf("TPM_Process_EstablishTransport: Error, "
+ "key keyUsage %04hx must be TPM_KEY_STORAGE or TPM_KEY_LEGACY\n",
+ encKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* b. If encHandle -> authDataUsage does not equal TPM_AUTH_NEVER and tag is NOT
+ TPM_TAG_RQU_AUTH1_COMMAND return TPM_AUTHFAIL */
+ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if (encKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_EstablishTransport: Error, "
+ "encKey authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get encHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Key_GetUsageAuth(&encKeyUsageAuth, encKey);
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ encKey,
+ encKeyUsageAuth, /* OIAP */
+ encKey->tpm_store_asymkey->
+ pubDataDigest); /*OSAP */
+ }
+ /* c. Using encHandle -> usageAuth, validate the AuthData to use the key and the
+ parameters to the command */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ keyAuth); /* Authorization digest for input */
+ }
+ /* d. Create K1 a TPM_TRANSPORT_AUTH structure by decrypting secret using the key
+ pointed to by encHandle */
+ /* e. Validate K1 for tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportAuth_DecryptSecret(&k1TransportAuth,
+ &secret,
+ encKey);
+
+ }
+ /* f. Set A1 to K1 -> authData */
+ if (returnCode == TPM_SUCCESS) {
+ a1AuthData = &(k1TransportAuth.authData);
+ TPM_PrintFour("TPM_Process_EstablishTransport: transport decrypted authData",
+ *a1AuthData);
+ }
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_EstablishTransport: transport authData", *a1AuthData);
+ }
+ /* 3. If transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT */
+ if ((returnCode == TPM_SUCCESS) && (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT)) {
+ printf("TPM_Process_EstablishTransport: Check encrypt attributes\n");
+ /* a. If TPM_PERMANENT_FLAGS -> FIPS is true and transPublic -> algId is equal to
+ TPM_ALG_MGF1 return TPM_INAPPROPRIATE_ENC */
+ /* b. Check if the transPublic -> algId is supported, if not return TPM_BAD_KEY_PROPERTY */
+ /* c. If transPublic -> algid is TPM_ALG_AESXXX, check that transPublic -> encScheme is
+ supported, if not return TPM_INAPPROPRIATE_ENC */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize,
+ transPublic.algId,
+ transPublic.encScheme,
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ /* d. Perform any initializations necessary for the algorithm */
+ }
+ /* 4. Generate transNonceEven from the TPM RNG */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Generate(transNonceEven);
+ }
+ /* 5. Create T1 a TPM_TRANSPORT_INTERNAL structure */
+ /* NOTE Done by TPM_TransportInternal_Init() */
+ /* a. Ensure that the TPM has sufficient internal space to allocate the transport session,
+ return TPM_RESOURCES on error */
+ /* b. Assign a T1 -> transHandle value. This value is assigned by the TPM */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_INTERNAL\n");
+ returnCode =
+ TPM_TransportSessions_GetNewHandle(&t1TpmTransportInternal,
+ tpm_state->tpm_stclear_data.transSessions);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* record that the entry is allocated, for invalidation on error */
+ trans_session_added = TRUE;
+ /* c. Set T1 -> transDigest to NULL */
+ TPM_Digest_Init(t1TpmTransportInternal->transDigest);
+ /* d. Set T1 -> transPublic to transPublic */
+ TPM_TransportPublic_Copy(&(t1TpmTransportInternal->transPublic), &transPublic);
+ /* e. Set T1-> transNonceEven to transNonceEven */
+ TPM_Nonce_Copy(t1TpmTransportInternal->transNonceEven , transNonceEven);
+ /* f. Set T1 -> authData to A1 */
+ TPM_Secret_Copy(t1TpmTransportInternal->authData, *a1AuthData);
+ /* 6. If TPM_STANY_DATA -> currentTicks is not properly initialized */
+ /* a. Initialize the TPM_STANY_DATA -> currentTicks */
+ returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks));
+ }
+ /* 7. Set currentTicks to TPM_STANY_DATA -> currentTicks */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_CurrentTicks_Copy(&currentTicks, &(tpm_state->tpm_stany_data.currentTicks));
+ }
+ /* 8. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */
+ if ((returnCode == TPM_SUCCESS) &&
+ (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) {
+
+ printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_IN\n");
+ /* a. Create L1 a TPM_TRANSPORT_LOG_IN structure */
+ /* NOTE Done by TPM_TransportLogIn_Init() */
+ /* i. Set L1 -> parameters to SHA-1 (ordinal || transPublic || secretSize || secret) */
+ /* serialize transPublic */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportPublic_Store(&transPublicSbuffer, &transPublic);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the transPublic serialization results */
+ TPM_Sbuffer_Get(&transPublicSbuffer, &transPublicBuffer, &transPublicLength);
+ /* digest the fields */
+ nOrdinal = htonl(ordinal);
+ nSecretSize = htonl(secret.size);
+ returnCode = TPM_SHA1(l1TransportLogIn.parameters,
+ sizeof(TPM_COMMAND_CODE), &nOrdinal,
+ transPublicLength, transPublicBuffer,
+ sizeof(uint32_t), &nSecretSize,
+ secret.size, secret.buffer,
+ 0, NULL);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* ii. Set L1 -> pubKeyHash to NULL */
+ /* NOTE Done by TPM_TransportLogIn_Init() */
+ /* iii. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L1) */
+ printf("TPM_Process_EstablishTransport: Extend transDigest with input\n");
+ returnCode = TPM_TransportLogIn_Extend(t1TpmTransportInternal->transDigest,
+ &l1TransportLogIn);
+ }
+ /* b. Create L2 a TPM_TRANSPORT_LOG_OUT structure */
+ /* NOTE Done by TPM_TransportLogOut_Init() */
+ /* i. Set L2 -> parameters to SHA-1 (returnCode || ordinal || locality || currentTicks ||
+ transNonceEven) */
+ /* serialize currentTicks */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_OUT\n");
+ returnCode = TPM_CurrentTicks_Store(&currentTicksSbuffer, &currentTicks);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the currentTicks serialization results */
+ TPM_Sbuffer_Get(&currentTicksSbuffer, &currentTicksBuffer, &currentTicksLength);
+ nReturnCode = htonl(returnCode);
+ nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier);
+ returnCode = TPM_SHA1(l2TransportLogOut.parameters,
+ sizeof(TPM_RESULT), &nReturnCode,
+ sizeof(TPM_COMMAND_CODE), &nOrdinal,
+ sizeof(TPM_MODIFIER_INDICATOR), &nLocality,
+ currentTicksLength, currentTicksBuffer,
+ TPM_NONCE_SIZE, transNonceEven,
+ 0, NULL);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* ii. Set L2 -> locality to the locality of this command */
+ l2TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier;
+ /* iii. Set L2 -> currentTicks to currentTicks, this MUST be the same value that is
+ returned in the currentTicks parameter */
+ TPM_CurrentTicks_Copy(&(l2TransportLogOut.currentTicks), &currentTicks);
+ /* iv. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L2) */
+ printf("TPM_Process_EstablishTransport: Extend transDigest with output\n");
+ returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest,
+ &l2TransportLogOut);
+ }
+ }
+ /* 9. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_EXCLUSIVE then
+ set TPM_STANY_FLAGS -> transportExclusive to TRUE */
+ if (returnCode == TPM_SUCCESS) {
+ if (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE) {
+ printf("TPM_Process_EstablishTransport: Session is exclusive\n");
+ tpm_state->tpm_stany_flags.transportExclusive = t1TpmTransportInternal->transHandle;
+ }
+ }
+ /* a. Execution of any command other than TPM_ExecuteTransport or TPM_ReleaseTransportSigned
+ targeting this transport session will cause the abnormal invalidation of this transport
+ session transHandle */
+ /* b. The TPM gives no indication, other than invalidation of transHandle, that the session is
+ terminated */
+ /* NOTE Done by TPM_Process_Preprocess() */
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_EstablishTransport: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ /* 10. Return T1 -> transHandle as transHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append32(response, t1TpmTransportInternal->transHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return locality */
+ returnCode = TPM_Sbuffer_Append32(response,
+ tpm_state->tpm_stany_flags.localityModifier);
+ }
+ /* return currentTicks */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CurrentTicks_Store(response, &currentTicks);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* return transNonceEven */
+ returnCode = TPM_Nonce_Store(response, transNonceEven);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING))) &&
+ trans_session_added) {
+ TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions,
+ t1TpmTransportInternal->transHandle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ /*
+ cleanup
+ */
+ TPM_TransportPublic_Delete(&transPublic); /* @1 */
+ TPM_SizedBuffer_Delete(&secret); /* @2 */
+ TPM_TransportAuth_Delete(&k1TransportAuth); /* @4 */
+ TPM_TransportLogIn_Delete(&l1TransportLogIn); /* @5 */
+ TPM_TransportLogOut_Delete(&l2TransportLogOut); /* @6 */
+ TPM_Sbuffer_Delete(&transPublicSbuffer); /* @7 */
+ TPM_Sbuffer_Delete(&currentTicksSbuffer); /* @8 */
+ return rcf;
+}
+
+/* 24.2 TPM_ExecuteTransport rev 117
+
+ Delivers a wrapped TPM command to the TPM where the TPM unwraps the command and then executes the
+ command.
+
+ TPM_ExecuteTransport uses the same rolling nonce paradigm as other authorized TPM commands. The
+ even nonces start in EstablishTransport and change on each invocation of TPM_ExecuteTransport.
+
+ The only restriction on what can happen inside of a transport session is that there is no
+ "nesting" of sessions. It is permissible to perform operations that delete internal state and
+ make the TPM inoperable.
+
+ Because, in general, key handles are not logged, a digest of the corresponding public key is
+ logged. In cases where the key handle is logged (e.g. TPM_OwnerReadInternalPub), the
+ public key is also logged.
+
+ The wrapped command is audited twice - once according to the actions of TPM_ExecuteTransport and
+ once within the wrapped command itself according to the special rules for auditing a command
+ wrapped in an encrypted transport session.
+*/
+
+TPM_RESULT TPM_Process_ExecuteTransport(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_SIZED_BUFFER wrappedCmd; /* The wrapped command */
+ TPM_TRANSHANDLE transHandle; /* The transport session handle */
+ TPM_NONCE transNonceOdd; /* Nonce generated by caller */
+ TPM_BOOL continueTransSession; /* The continue use flag for the authorization
+ session handle */
+ TPM_AUTHDATA transAuth; /* HMAC for transHandle key: transHandle ->
+ authData */
+
+ /* processing parameters */
+ /* unsigned char * inParamStart; /\* starting point of inParam's *\/ */
+ /* unsigned char * inParamEnd; /\* ending point of inParam's *\/ */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transHandleValid = FALSE;
+ TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal;
+ TPM_TRANSPORT_INTERNAL t1TransportCopy; /* because original might be invalidated */
+ TPM_BOOL transportWrappable; /* inner command can be wrapped in
+ transport */
+ uint32_t keyHandles; /* number of key handles in ordw */
+ uint32_t keyHandle1Index; /* index of key handles in wrapped command */
+ uint32_t keyHandle2Index;
+ TPM_KEY_HANDLE keyHandle1; /* key handles in wrapped command */
+ TPM_KEY_HANDLE keyHandle2;
+ uint32_t blockSize; /* symmetric key block size, if needed */
+ TPM_RESOURCE_TYPE wrappedResourceType; /* for key handle special cases */
+ TPM_COMMAND_CODE ordw; /* wrapped ORDW */
+ uint32_t e1Dataw; /* index into wrapped E1 */
+ uint32_t len1; /* wrapped LEN1 */
+ unsigned char *g1Mgf1; /* input MGF1 XOR string */
+ unsigned char *g2Mgf1; /* output MGF1 XOR string */
+ unsigned char *decryptCmd; /* decrypted wrapped command */
+ unsigned char *cmdStream; /* temporary for constructing decryptCmd */
+ uint32_t cmdStreamSize;
+ TPM_COMMAND_CODE nOrdw; /* ordinal in nbo */
+ TPM_COMMAND_CODE nOrdet; /* ordinal in nbo */
+ uint32_t nWrappedCmdSize; /* wrappedCmdSize in nbo */
+ TPM_DIGEST h1InWrappedDigest;
+ TPM_DIGEST h2OutWrappedDigest;
+ TPM_TRANSPORT_LOG_IN l2TransportLogIn;
+ TPM_TRANSPORT_LOG_OUT l3TransportLogOut;
+ TPM_DIGEST k2PubkeyDigest;
+ TPM_DIGEST k3PubkeyDigest;
+ TPM_KEY *k2Key; /* wrapped command keys */
+ TPM_KEY *k3Key;
+ TPM_BOOL parentPCRStatus;
+ TPM_STORE_BUFFER wrappedRspSbuffer;
+ const unsigned char *wrappedRspStream;
+ uint32_t wrappedRspStreamSize;
+ uint32_t s2Dataw; /* index into S2 */
+ uint32_t len2; /* length of S2 */
+ TPM_RESULT rcw; /* wrapped return code */
+ TPM_RESULT nRcw; /* return code in nbo */
+ TPM_STORE_BUFFER currentTicksSbuffer;
+ const unsigned char *currentTicksBuffer; /* serialized buffer */
+ uint32_t currentTicksLength; /* serialization length */
+ TPM_RESULT nRCet; /* return code in nbo */
+ TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */
+ uint32_t nWrappedRspStreamSize; /* wrappedRspStreamSize in nbo */
+ unsigned char *encryptRsp; /* encrypted response */
+
+ /* output parameters */
+ TPM_DIGEST outParamDigest;
+ TPM_UINT64 currentTicks; /* The current ticks when the command was
+ executed */
+ TPM_SIZED_BUFFER wrappedRsp; /* The wrapped response */
+
+ printf("TPM_Process_ExecuteTransport: Ordinal Entry\n");
+ transportInternal = transportInternal; /* TPM_ExecuteTransport cannot be wrapped */
+ TPM_SizedBuffer_Init(&wrappedCmd); /* freed @1 */
+ TPM_SizedBuffer_Init(&wrappedRsp); /* freed @2 */
+ g1Mgf1 = NULL; /* freed @3 */
+ decryptCmd = NULL; /* freed @4 */
+ TPM_TransportLogIn_Init(&l2TransportLogIn); /* freed @5 */
+ TPM_TransportLogOut_Init(&l3TransportLogOut); /* freed @6 */
+ TPM_Sbuffer_Init(&wrappedRspSbuffer); /* freed @7 */
+ TPM_Sbuffer_Init(&currentTicksSbuffer); /* freed @8 */
+ g2Mgf1 = NULL; /* freed @9 */
+ TPM_TransportInternal_Init(&t1TransportCopy); /* freed @10 */
+ encryptRsp = NULL; /* freed @11 */
+ /*
+ get inputs
+ */
+ if (returnCode == TPM_SUCCESS) {
+ /* save the starting point of inParam's for authorization and auditing */
+ /* inParamStart = command; */
+ /* get wrappedCmd */
+ returnCode = TPM_SizedBuffer_Load(&wrappedCmd, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: wrapped command size %u\n", wrappedCmd.size);
+ /* save the ending point of inParam's for authorization and auditing */
+ /* inParamEnd = command; */
+ /* NOTE: The common TPM_GetInParamDigest() is not called here, since inParamDigest cannot be
+ calculated until the wrapped command is decrypted */
+ returnCode = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus,
+ ordinal,
+ &(tpm_state->tpm_permanent_data));
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&transHandle,
+ &transHandleValid,
+ transNonceOdd,
+ &continueTransSession,
+ transAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: transHandle %08x\n", transHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ExecuteTransport: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ transHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* if there is an active exclusive transport session and it's not this session, terminate it */
+ if (returnCode == TPM_SUCCESS) {
+ if ((tpm_state->tpm_stany_flags.transportExclusive != 0) &&
+ (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) {
+ returnCode = TPM_TransportSessions_TerminateHandle
+ (tpm_state->tpm_stclear_data.transSessions,
+ tpm_state->tpm_stany_flags.transportExclusive,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ }
+ /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal,
+ tpm_state->tpm_stclear_data.transSessions,
+ transHandle);
+ }
+ /* For the corner case where the wrapped command invalidates the transport session, make a copy
+ for the response. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_TransportInternal_Copy(&t1TransportCopy,
+ t1TpmTransportInternal);
+ }
+ /* 2. Parse wrappedCmd */
+ /* a. Set TAGw, LENw, and ORDw to the parameters from wrappedCmd */
+ /* b. Set E1 to DATAw */
+ /* i. This pointer is ordinal dependent and requires the execute transport command to parse
+ wrappedCmd */
+ /* c. Set LEN1 to the length of DATAw */
+ /* i. DATAw always ends at the start of AUTH1w if AUTH1w is present */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_OrdinalTable_ParseWrappedCmd(&e1Dataw, /* index into wrappedCmd */
+ &len1,
+ &keyHandles,
+ &keyHandle1Index, /* index into key handles */
+ &keyHandle2Index,
+ &ordw,
+ &transportWrappable,
+ &wrappedCmd);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Error parsing wrapped command\n");
+ }
+ }
+ /* 3. If LEN1 is less than 0, or if ORDw is unknown, unimplemented, or cannot be determined
+ a. Return TPM_BAD_PARAMETER */
+ if (returnCode == TPM_SUCCESS) {
+ if (wrappedCmd.size < e1Dataw + len1) {
+ printf("TPM_Process_ExecuteTransport: Error (fatal), wrappedCmdSize %u e1 %u len1 %u\n",
+ wrappedCmd.size, e1Dataw, len1);
+ returnCode = TPM_FAIL; /* internal error, should never occur */
+ }
+ }
+ /* allocate memory for the decrypted command, which is always the same length as the encrypted
+ command */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Malloc(&decryptCmd, wrappedCmd.size);
+ }
+ /* 4. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */
+ if ((returnCode == TPM_SUCCESS) &&
+ (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) &&
+ (len1 != 0)) { /* some commands have no DATAw area to encrypt */
+ /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */
+ if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) {
+ printf("TPM_Process_ExecuteTransport: Wrapped command MGF1 encrypted\n");
+ /* i. Using the MGF1 function, create string G1 of length LEN1. The inputs to the MGF1
+ are transLastNonceEven, transNonceOdd, "in", and T1 -> authData. These four values
+ concatenated together form the Z value that is the seed for the MGF1. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */
+ len1, /* G1 length */
+
+ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1 +
+ TPM_AUTHDATA_SIZE, /* seed length */
+
+ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven,
+ TPM_NONCE_SIZE, transNonceOdd,
+ sizeof("in") - 1, "in",
+ TPM_AUTHDATA_SIZE, t1TransportCopy.authData,
+ 0, NULL);
+ }
+ /* ii. Create C1 by performing an XOR of G1 and wrappedCmd starting at E1. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Transport_CryptMgf1(decryptCmd, /* output */
+ wrappedCmd.buffer, /* input */
+ g1Mgf1, /* XOR pad */
+ wrappedCmd.size, /* total size of buffers */
+ e1Dataw, /* start of encrypted part */
+ len1); /* length of encrypted part */
+ }
+ }
+ /* b. If the encryption algorithm requires an IV or CTR calculate the IV or CTR value */
+ else {
+ printf("TPM_Process_ExecuteTransport: "
+ "Wrapped command algId %08x encScheme %04hx encrypted\n",
+ t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme);
+ /* This function call should not fail, as the parameters were checked at
+ TPM_EstablishTransport. The call is used here to get the block size. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_TransportPublic_CheckEncScheme(&blockSize,
+ t1TransportCopy.transPublic.algId,
+ t1TransportCopy.transPublic.encScheme,
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ /* i. Using the MGF1 function, create string IV1 or CTR1 with a length set by the block
+ size of the encryption algorithm. The inputs to the MGF1 are transLastNonceEven,
+ transNonceOdd, and "in". These three values concatenated together form the Z value
+ that is the seed for the MGF1. Note that any terminating characters within the string
+ "in" are ignored, so a total of 42 bytes are hashed. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */
+ blockSize, /* G1 length */
+
+ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1,
+ /* seed length */
+
+ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven,
+ TPM_NONCE_SIZE, transNonceOdd,
+ sizeof("in") - 1, "in",
+ 0, NULL);
+ }
+ /* ii. The symmetric key is taken from the first bytes of T1 -> authData. */
+ /* iii. Decrypt DATAw and replace the DATAw area of E1 creating C1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_Transport_CryptSymmetric(decryptCmd, /* output */
+ wrappedCmd.buffer, /* input */
+ t1TransportCopy.transPublic.algId,
+ t1TransportCopy.transPublic.encScheme,
+ t1TransportCopy.authData, /* key */
+ TPM_AUTHDATA_SIZE, /* key size */
+ g1Mgf1, /* pad, IV or CTR */
+ blockSize,
+ wrappedCmd.size, /* total size of buffers */
+ e1Dataw, /* start of encrypted part */
+ len1); /* length of encrypted part */
+ }
+ }
+ /* 4.c. TPM_OSAP, TPM_OIAP have no parameters encrypted */
+ /* NOTE Handled by len1 = 0 */
+ /* 4.d. TPM_DSAP has special rules for parameter encryption */
+ /* NOTE Handled by setting inputHandleSize to all but entityValue */
+ }
+ /* 5. Else (no encryption) */
+ else if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Wrapped command not encrypted\n");
+ /* a. Set C1 to the DATAw area E1 of wrappedCmd */
+ memcpy(decryptCmd, wrappedCmd.buffer, wrappedCmd.size);
+ }
+
+ /* Now that the wrapped command is decrypted, handle the special cases (e.g., TPM_FlushSpecific
+ and TPM_SaveContext) where the handle may or may not be a key handle, dependent on the value
+ of resourceType */
+ if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) {
+ printf("TPM_Process_ExecuteTransport: key handles special case\n");
+
+ /* point to the resourceType in the decrypted stream, directly after the key handle */
+ cmdStream = decryptCmd + keyHandle1Index + sizeof(TPM_KEY_HANDLE);
+ cmdStreamSize = wrappedCmd.size - keyHandle1Index - sizeof(TPM_KEY_HANDLE);
+ returnCode = TPM_Load32(&wrappedResourceType, &cmdStream , &cmdStreamSize );
+ }
+ /* ii. If the resourceType is TPM_RT_KEY, then the public key MUST be logged */
+ if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) {
+ printf("TPM_Process_ExecuteTransport: special case resource type %08x\n",
+ wrappedResourceType);
+ if (wrappedResourceType == TPM_RT_KEY) {
+ printf("TPM_Process_ExecuteTransport: Special case, 1 key handle\n");
+ keyHandles = 1;
+ }
+ else {
+ keyHandles = 0;
+ }
+ }
+
+ /* 6. Create H1 the SHA-1 of (ORDw || C1). */
+ /* a. C1 MUST point at the decrypted DATAw area of E1 */
+ /* b. The TPM MAY use this calculation for both execute transport authorization, authorization
+ of the wrapped command and transport log creation */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ExecuteTransport: DATAw decrypted", decryptCmd);
+ printf("TPM_Process_ExecuteTransport: Create H1\n");
+ nOrdw = htonl(ordw);
+ returnCode = TPM_SHA1(h1InWrappedDigest,
+ sizeof(TPM_COMMAND_CODE), &nOrdw,
+ len1, decryptCmd + e1Dataw,
+ 0, NULL);
+ }
+ /* 7. Validate the incoming transport session authorization */
+ /* a. Set inParamDigest to SHA-1 (ORDet || wrappedCmdSize || H1) */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Validate AUTHet\n");
+ nOrdet = htonl(ordinal);
+ nWrappedCmdSize = htonl(wrappedCmd.size);
+ returnCode = TPM_SHA1(inParamDigest,
+ sizeof(TPM_COMMAND_CODE), &nOrdet,
+ sizeof(uint32_t), &nWrappedCmdSize,
+ TPM_DIGEST_SIZE, h1InWrappedDigest,
+ 0, NULL);
+ }
+ /* b. Calculate the HMAC of (inParamDigest || transLastNonceEven || transNonceOdd ||
+ continueTransSession) using T1 -> authData as the HMAC key */
+ /* c. Validate transAuth, on errors return TPM_AUTHFAIL */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_TransportInternal_Check(inParamDigest,
+ &t1TransportCopy, /* transport session */
+ transNonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueTransSession,
+ transAuth); /* Authorization digest for input */
+ }
+ /* 8. If TPM_ExecuteTransport requires auditing */
+ /* a. Create TPM_AUDIT_EVENT_IN using H1 */
+ /* NOTE: Done during response */
+ /* 9. If ORDw is from the list of following commands return TPM_NO_WRAP_TRANSPORT */
+ /* a. TPM_EstablishTransport */
+ /* b. TPM_ExecuteTransport */
+ /* c. TPM_ReleaseTransportSigned */
+ if (returnCode == TPM_SUCCESS) {
+ if (!transportWrappable) {
+ printf("TPM_Process_ExecuteTransport: Error, ordinal %08x cannot be wrapped\n",
+ ordw);
+ returnCode = TPM_NO_WRAP_TRANSPORT;
+ }
+ }
+ /* 10. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */
+ if ((returnCode == TPM_SUCCESS) &&
+ (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) {
+ printf("TPM_Process_ExecuteTransport: Create transport log\n");
+ /* a. Create L2 a TPM_TRANSPORT_LOG_IN structure */
+ /* NOTE Done by TPM_TransportLogIn_Init() */
+ /* b. Set L2 -> parameters to H1 */
+ TPM_Digest_Copy(l2TransportLogIn.parameters, h1InWrappedDigest);
+ /* c. If ORDw is a command with no key handles */
+ /* i. Set L2 -> pubKeyHash to NULL */
+ /* NOTE Done by TPM_TransportLogIn_Init() */
+ if ((returnCode == TPM_SUCCESS) && ((keyHandles == 1) || (keyHandles == 2))) {
+ if (returnCode == TPM_SUCCESS) {
+ /* point to the first key handle in the decrypted stream */
+ cmdStream = decryptCmd + keyHandle1Index;
+ cmdStreamSize = wrappedCmd.size - keyHandle1Index;
+ /* get the key handle */
+ returnCode = TPM_Load32(&keyHandle1, &cmdStream, &cmdStreamSize);
+ }
+ /* get the first key */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 1 handle %08x\n",
+ keyHandle1);
+ returnCode = TPM_KeyHandleEntries_GetKey(&k2Key,
+ &parentPCRStatus,
+ tpm_state,
+ keyHandle1,
+ TRUE, /* read-only */
+ FALSE, /* do not ignore PCRs */
+ TRUE); /* can use EK */
+ }
+ /* 10.d. If ORDw is a command with one key handle */
+ /* 10.i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by
+ the key handle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_SHA1_GenerateStructure(k2PubkeyDigest,
+ &(k2Key->pubKey),
+ (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store);
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (keyHandles == 1)) {
+ printf("TPM_Process_ExecuteTransport: Digesting one public key\n");
+ /* 10.ii. Set L2 -> pubKeyHash to SHA-1 (K2) */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash,
+ TPM_DIGEST_SIZE, k2PubkeyDigest,
+ 0, NULL);
+ }
+ }
+ /* 10.e. If ORDw is a command with two key handles */
+ if ((returnCode == TPM_SUCCESS) && (keyHandles == 2)) {
+ printf("TPM_Process_ExecuteTransport: Digesting two public keys\n");
+ /* i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the
+ first key handle. */
+ /* NOTE Done above for 1 or 2 key case */
+ if (returnCode == TPM_SUCCESS) {
+ /* point to the second key handle in the decrypted stream */
+ cmdStream = decryptCmd + keyHandle2Index;
+ cmdStreamSize = wrappedCmd.size - keyHandle2Index;
+ /* get the key handle */
+ returnCode = TPM_Load32(&keyHandle2, &cmdStream, &cmdStreamSize);
+ }
+ /* get the second key */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 2 handle %08x\n",
+ keyHandle2);
+ returnCode = TPM_KeyHandleEntries_GetKey(&k3Key,
+ &parentPCRStatus,
+ tpm_state,
+ keyHandle2,
+ TRUE, /* read-only */
+ FALSE, /* do not ignore PCRs */
+ TRUE); /* can use EK */
+ }
+ /* ii. Create K3 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the
+ second key handle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_SHA1_GenerateStructure(k3PubkeyDigest,
+ &(k3Key->pubKey),
+ (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store);
+ }
+ /* 10.iii. Set L2 -> pubKeyHash to SHA-1 (K2 || K3) */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash,
+ TPM_DIGEST_SIZE, k2PubkeyDigest,
+ TPM_DIGEST_SIZE, k3PubkeyDigest,
+ 0, NULL);
+ }
+ }
+ /* 10.f. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L2) */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Extend transDigest with input\n");
+ returnCode = TPM_TransportLogIn_Extend(t1TransportCopy.transDigest,
+ &l2TransportLogIn);
+ }
+ /* 10.g. If ORDw is a command with key handles, and the key is not loaded, return
+ TPM_INVALID_KEYHANDLE. */
+ /* NOTE Done by TPM_KeyHandleEntries_GetKey() */
+ }
+ /* 11. Send the wrapped command to the normal TPM command parser, the output is C2 and the
+ return code is RCw */
+ /* a. If ORDw is a command that is audited then the TPM MUST perform the input and output audit
+ of the command as part of this action */
+ /* b. The TPM MAY use H1 as the data value in the authorization and audit calculations during
+ the execution of C1 */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Call wrapped command\n");
+ returnCode = TPM_Process_Wrapped(&wrappedRspSbuffer, /* response buffer */
+ decryptCmd, /* complete command array */
+ wrappedCmd.size, /* actual bytes in command */
+ tpm_state,
+ &t1TransportCopy); /* TPM_ExecuteTransport */
+ printf("TPM_Process_ExecuteTransport: Completed wrapped command\n");
+ }
+ /* 12. Set CT1 to TPM_STANY_DATA -> currentTicks -> currentTicks and return CT1 in the
+ currentTicks output parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks));
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_Uint64_Copy(&currentTicks, &(tpm_state->tpm_stany_data.currentTicks.currentTicks));
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Uint64_Store(&currentTicksSbuffer,
+ &(tpm_state->tpm_stany_data.currentTicks.currentTicks));
+ }
+ /* 13. Calculate S2 the pointer to the DATAw area of C2 */
+ /* a. Calculate LEN2 the length of S2 according to the same rules that calculated LEN1 */
+ if (returnCode == TPM_SUCCESS) {
+ /* get the response buffer and length */
+ TPM_Sbuffer_Get(&wrappedRspSbuffer, &wrappedRspStream, &wrappedRspStreamSize);
+ /* parse the three standard input parameters, check paramSize against wrappedRsp->size */
+ returnCode = TPM_OrdinalTable_ParseWrappedRsp(&s2Dataw,
+ &len2,
+ &rcw,
+ ordw,
+ wrappedRspStream,
+ wrappedRspStreamSize);
+ }
+ /* 14. Create H2 the SHA-1 of (RCw || ORDw || S2) */
+ /* a. The TPM MAY use this calculation for execute transport authorization and transport log out
+ creation */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Create H2\n");
+ nRcw = htonl(rcw);
+ /* The TPM_ExecuteTransport input ordinal and output ordinal, currentTicks and locality are
+ not audited. This was simply an error, and not a deliberate attempt to make
+ TPM_ExecuteTransport different from other ordinals. */
+ returnCode = TPM_SHA1(h2OutWrappedDigest,
+ sizeof(TPM_RESULT), &nRcw,
+ sizeof(TPM_COMMAND_CODE), &nOrdw,
+ len2, wrappedRspStream + s2Dataw,
+ 0, NULL);
+ }
+ /* 15. Calculate the outgoing transport session authorization */
+ /* a. Create the new transNonceEven for the output of the command */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Generate(t1TransportCopy.transNonceEven);
+ }
+ /* b. Set outParamDigest to SHA-1 (RCet || ORDet || TPM_STANY_DATA -> currentTicks ->
+ currentTicks || locality || wrappedRspSize || H2) */
+ if (returnCode == TPM_SUCCESS) {
+ nRCet = htonl(returnCode);
+ TPM_Sbuffer_Get(&currentTicksSbuffer, &currentTicksBuffer, &currentTicksLength);
+ nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier);
+ nWrappedRspStreamSize = htonl(wrappedRspStreamSize);
+ returnCode = TPM_SHA1(outParamDigest,
+ sizeof(TPM_RESULT), &nRCet,
+ sizeof(TPM_COMMAND_CODE), &nOrdet,
+ currentTicksLength, currentTicksBuffer,
+ sizeof(TPM_MODIFIER_INDICATOR), &nLocality,
+ sizeof(uint32_t), &nWrappedRspStreamSize,
+ TPM_DIGEST_SIZE, h2OutWrappedDigest,
+ 0, NULL);
+ }
+ /* c. Calculate transAuth, the HMAC of (outParamDigest || transNonceEven || transNonceOdd ||
+ continueTransSession) using T1 -> authData as the HMAC key */
+ /* NOTE: Done as part of response */
+ /* 16. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */
+ if ((returnCode == TPM_SUCCESS) &&
+ (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) {
+ /* a. Create L3 a TPM_TRANSPORT_LOG_OUT structure */
+ /* NOTE Done by TPM_TransportLogOut_Init() */
+ /* b. Set L3 -> parameters to H2 */
+ TPM_Digest_Copy(l3TransportLogOut.parameters, h2OutWrappedDigest);
+ /* c. Set L3 -> currentTicks to TPM_STANY_DATA -> currentTicks */
+ TPM_CurrentTicks_Copy(&(l3TransportLogOut.currentTicks),
+ &(tpm_state->tpm_stany_data.currentTicks));
+ /* d. Set L3 -> locality to TPM_STANY_DATA -> localityModifier */
+ l3TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier;
+ /* e. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L3) */
+ printf("TPM_Process_ExecuteTransport: Extend transDigest with output\n");
+ returnCode = TPM_TransportLogOut_Extend(t1TransportCopy.transDigest,
+ &l3TransportLogOut);
+ }
+ /* allocate memory for the encrypted response, which is always the same length as the decrypted
+ response */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Malloc(&encryptRsp, wrappedRspStreamSize);
+ }
+ /* 17. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */
+ if ((returnCode == TPM_SUCCESS) &&
+ (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) &&
+ (len2 != 0)) { /* some commands have no DATAw area to encrypt */
+ /* NOTE No TPM_OSAP encryption handled by len2 = 0 */
+ /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */
+ if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) {
+ printf("TPM_Process_ExecuteTransport: Wrapped response MGF1 encrypted\n");
+ /* i. Using the MGF1 function, create string G2 of length LEN2. The inputs to the MGF1
+ are transNonceEven, transNonceOdd, "out", and T1 -> authData. These four values
+ concatenated together form the Z value that is the seed for the MGF1. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */
+ len2, /* G2 length */
+
+ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1 +
+ TPM_AUTHDATA_SIZE, /* seed length */
+
+ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven,
+ TPM_NONCE_SIZE, transNonceOdd,
+ sizeof("out") - 1, "out",
+ TPM_AUTHDATA_SIZE, t1TransportCopy.authData,
+ 0, NULL);
+ }
+ /* ii. Create E2 by performing an XOR of G2 and C2 starting at S2. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Transport_CryptMgf1(encryptRsp,
+ wrappedRspStream,
+ g2Mgf1,
+ wrappedRspStreamSize,
+ s2Dataw,
+ len2);
+ }
+ }
+ /* b. Else */
+ else {
+ printf("TPM_Process_ExecuteTransport: "
+ "Wrapped response algId %08x encScheme %04hx encrypted\n",
+ t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme);
+ /* This function call should not fail, as the parameters were checked at
+ TPM_EstablishTransport. The call is used here to get the block size.
+
+ This is a duplicate of the call for the command. However, there are cases where
+ there is no encrypted command (len1 == 0) so the call was not made. Rather than
+ keep track of whether blockSize is valid, it's clearer to just call the function
+ twice in some cases.
+ */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_TransportPublic_CheckEncScheme(&blockSize,
+ t1TransportCopy.transPublic.algId,
+ t1TransportCopy.transPublic.encScheme,
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ /* i. Create IV2 or CTR2 using the same algorithm as IV1 or CTR1 with the input values
+ transNonceEven, transNonceOdd, and "out". Note that any terminating characters within
+ the string "out" are ignored, so a total of 43 bytes are hashed. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */
+ blockSize, /* G2 length */
+
+ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1,
+ /* seed length */
+
+ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven,
+ TPM_NONCE_SIZE, transNonceOdd,
+ sizeof("out") - 1, "out",
+ 0, NULL);
+ }
+ /* ii. The symmetric key is taken from the first bytes of T1 -> authData */
+ /* iii. Create E2 by encrypting C2 starting at S2 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_Transport_CryptSymmetric(encryptRsp, /* output */
+ wrappedRspStream, /* input */
+ t1TransportCopy.transPublic.algId,
+ t1TransportCopy.transPublic.encScheme,
+ t1TransportCopy.authData, /* key */
+ TPM_AUTHDATA_SIZE, /* key size */
+ g2Mgf1, /* pad, IV or CTR */
+ blockSize,
+ wrappedRspStreamSize, /* total size of buffers */
+ s2Dataw, /* start of encrypted part */
+ len2); /* length of encrypted part */
+ }
+ }
+ }
+ /* 18. Else (no encryption) */
+ else if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ExecuteTransport: Wrapped response not encrypted\n");
+ /* a. Set E2 to the DATAw area S2 of wrappedRsp */
+ memcpy(encryptRsp, wrappedRspStream ,wrappedRspStreamSize);
+ }
+ /* 19. If continueTransSession is FALSE */
+ /* a. Invalidate all session data related to transHandle */
+ /* NOTE: Done after response */
+ /* 20. If TPM_ExecuteTranport requires auditing */
+ /* a. Create TPM_AUDIT_EVENT_OUT using H2 */
+ /* NOTE: Done during response */
+ /* 21. Return C2 but with S2 replaced by E2 in the wrappedRsp parameter */
+ if (returnCode == TPM_SUCCESS) {
+ /* if the wrapped command invalidated the transport session, set continueTransSession to
+ FALSE */
+ if (!(t1TpmTransportInternal->valid)) {
+ continueTransSession = FALSE;
+ }
+ /* if the session is still valid, copy the copy back to the original so the log gets
+ updated */
+ else {
+ TPM_TransportInternal_Copy(t1TpmTransportInternal, &t1TransportCopy);
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ExecuteTransport: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ /* return currentTicks */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append(response, currentTicksBuffer, currentTicksLength);
+ }
+ /* return locality */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append32(response,
+ tpm_state->tpm_stany_flags.localityModifier);
+ }
+ /* return wrappedRspSize */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append32(response, wrappedRspStreamSize);
+ }
+ /* return wrappedRsp */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append(response, encryptRsp, wrappedRspStreamSize);
+ }
+ /* non-standard - digest the above the line output parameters, H1 used */
+ /* non-standard - calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportInternal_Set(response,
+ &t1TransportCopy,
+ outParamDigest,
+ transNonceOdd,
+ continueTransSession,
+ FALSE); /* transNonceEven already generated */
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ FALSE, /* transportEncrypt */
+ h1InWrappedDigest,
+ h2OutWrappedDigest, /* exception to normal digest */
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueTransSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueTransSession) &&
+ transHandleValid) {
+ TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions,
+ transHandle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&wrappedCmd); /* @1 */
+ TPM_SizedBuffer_Delete(&wrappedRsp); /* @2 */
+ free(g1Mgf1); /* @3 */
+ free (decryptCmd); /* @4 */
+ TPM_TransportLogIn_Delete(&l2TransportLogIn); /* @5 */
+ TPM_TransportLogOut_Delete(&l3TransportLogOut); /* @6 */
+ TPM_Sbuffer_Delete(&wrappedRspSbuffer); /* @7 */
+ TPM_Sbuffer_Delete(&currentTicksSbuffer); /* @8 */
+ free(g2Mgf1); /* @9 */
+ TPM_TransportInternal_Delete(&t1TransportCopy); /* @10 */
+ free(encryptRsp); /* @11 */
+ return rcf;
+}
+
+/* 24.3 TPM_ReleaseTransportSigned rev 101
+
+ This command completes the transport session. If logging for this session is turned on, then this
+ command returns a hash of all operations performed during the session along with a digital
+ signature of the hash.
+
+ This command serves no purpose if logging is turned off, and results in an error if attempted.
+
+ This command uses two authorization sessions, the key that will sign the log and the
+ authorization from the session. Having the session authorization proves that the requester that
+ is signing the log is the owner of the session. If this restriction is not put in then an
+ attacker can close the log and sign using their own key.
+
+ The hash of the session log includes the information associated with the input phase of execution
+ of the TPM_ReleaseTransportSigned command. It cannot include the output phase information.
+*/
+
+TPM_RESULT TPM_Process_ReleaseTransportSigned(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that will perform the signing */
+ TPM_NONCE antiReplay; /* Value provided by caller for anti-replay protection */
+ TPM_AUTHHANDLE authHandle; /* The authorization session to use key */
+ TPM_NONCE authNonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session
+ handle */
+ TPM_AUTHDATA keyAuth; /* The authorization session digest that authorizes the use
+ of key. HMAC key: key -> usageAuth */
+ TPM_TRANSHANDLE transHandle; /* The transport session handle */
+ TPM_NONCE transNonceOdd; /* Nonce supplied by caller for transport session */
+ TPM_BOOL continueTransSession = TRUE; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA transAuth; /* HMAC for transport session key: tranHandle -> authData */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_BOOL transHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal = NULL;
+ TPM_SECRET *hmacKey;
+ TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */
+ TPM_BOOL parentPCRStatus;
+ TPM_SECRET *keyUsageAuth;
+ TPM_TRANSPORT_LOG_OUT a1TransportLogOut;
+ TPM_SIGN_INFO h1SignInfo;
+ TPM_DIGEST h1Digest; /* digest of h1SignInfo */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */
+ TPM_SIZED_BUFFER signature; /* The signature of the digest */
+
+ printf("TPM_Process_ReleaseTransportSigned: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&signature); /* freed @1 */
+ TPM_TransportLogOut_Init(&a1TransportLogOut); /* freed @2 */
+ TPM_SignInfo_Init(&h1SignInfo); /* freed @3 */
+ /*
+ get inputs
+
+ */
+ /* get keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get antiReplay */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReleaseTransportSigned: keyHandle %08x\n", keyHandle );
+ returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ReleaseTransportSigned: antiReplay", antiReplay);
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag21(tag);
+ }
+
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ authNonceOdd,
+ &continueAuthSession,
+ keyAuth,
+ &command, &paramSize);
+ printf("TPM_Process_ReleaseTransportSigned: authHandle %08x\n", authHandle);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&transHandle,
+ &transHandleValid,
+ transNonceOdd,
+ &continueTransSession,
+ transAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReleaseTransportSigned: transHandle %08x\n", transHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ReleaseTransportSigned: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ transHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* if there is an active exclusive transport session and it's not this session, terminate it */
+ if (returnCode == TPM_SUCCESS) {
+ if ((tpm_state->tpm_stany_flags.transportExclusive != 0) &&
+ (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) {
+ returnCode =
+ TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions,
+ tpm_state->tpm_stany_flags.transportExclusive,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ }
+ /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal,
+ tpm_state->tpm_stclear_data.transSessions,
+ transHandle);
+ }
+ /* get the key corresponding to the keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle,
+ FALSE, /* not r/o, used to sign */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or
+ TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */
+ if (returnCode == TPM_SUCCESS) {
+ if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) &&
+ (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) {
+ printf("TPM_Process_ReleaseTransportSigned: Error, invalid sigKey sigScheme %04hx\n",
+ sigKey->algorithmParms.sigScheme);
+ returnCode = TPM_INAPPROPRIATE_SIG;
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) {
+ if (sigKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_ReleaseTransportSigned: Error, authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get keyHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) {
+ returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey);
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ sigKey,
+ keyUsageAuth, /* OIAP */
+ sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */
+ }
+ /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, if not return
+ TPM_INVALID_KEYUSAGE */
+ if (returnCode == TPM_SUCCESS) {
+ if (sigKey ->keyUsage != TPM_KEY_SIGNING) {
+ printf("TPM_Process_ReleaseTransportSigned: Error, keyUsage %04hx is invalid\n",
+ sigKey ->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 4. Using key -> authData validate the command and parameters, on error return TPM_AUTHFAIL */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ authNonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ keyAuth); /* Authorization digest for input */
+ }
+ /* 5. Using transHandle -> authData validate the command and parameters, on error return
+ TPM_AUTH2FAIL */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_TransportInternal_Check(inParamDigest,
+ t1TpmTransportInternal, /* transport session */
+ transNonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueTransSession,
+ transAuth); /* Authorization digest for input */
+ }
+ /* 7. Else */
+ if (returnCode == TPM_SUCCESS) {
+ if (!(t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) {
+ /* a. Return TPM_BAD_MODE */
+ printf("TPM_Process_ReleaseTransportSigned: Error, TPM_TRANSPORT_LOG not set\n");
+ returnCode = TPM_BAD_MODE;
+ }
+ }
+ /* 6. If T1 -> transAttributes has TPM_TRANSPORT_LOG set then update the current ticks
+ structure */
+ if (returnCode == TPM_SUCCESS) {
+ currentTicks = &(tpm_state->tpm_stany_data.currentTicks);
+ /* update the ticks based on the current time */
+ returnCode = TPM_CurrentTicks_Update(currentTicks);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* a. Create A1 a TPM_TRANSPORT_LOG_OUT structure */
+ /* NOTE Done by TPM_TransportLogOut_Init() */
+ /* b. Set A1 -> parameters to the SHA-1 (ordinal || antiReplay) */
+ TPM_Digest_Copy(a1TransportLogOut.parameters, inParamDigest);
+ /* c. Set A1 -> currentTicks to TPM_STANY_DATA -> currentTicks */
+ TPM_CurrentTicks_Copy(&(a1TransportLogOut.currentTicks), currentTicks);
+ /* d. Set A1 -> locality to the locality modifier for this command */
+ a1TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier;
+ /* e. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || A1) */
+ printf("TPM_Process_ReleaseTransportSigned: Extend transDigest with output\n");
+ returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest,
+ &a1TransportLogOut);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 8. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */
+ /* NOTE: Done by TPM_SignInfo_Init() */
+ /* a. Set H1 -> fixed to "TRAN" */
+ memcpy(h1SignInfo.fixed, "TRAN", TPM_SIGN_INFO_FIXED_SIZE);
+ /* b. Set H1 -> replay to antiReplay */
+ TPM_Nonce_Copy(h1SignInfo.replay, antiReplay);
+ /* c. Set H1 -> data to T1 -> transDigest */
+ returnCode = TPM_SizedBuffer_Set(&(h1SignInfo.data),
+ TPM_DIGEST_SIZE,
+ t1TpmTransportInternal->transDigest);
+ }
+ /* d. Sign SHA-1 hash of H1 using the key pointed to by keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1_GenerateStructure(h1Digest, &h1SignInfo,
+ (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store);
+ TPM_PrintAll("TPM_Process_ReleaseTransportSigned: h1Digest", h1Digest, TPM_DIGEST_SIZE);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSASignToSizedBuffer(&signature, /* signature */
+ h1Digest, /* message */
+ TPM_DIGEST_SIZE, /* message size */
+ sigKey); /* input, signing key */
+ }
+ /* 9. Invalidate all session data related to T1 */
+ /* NOTE Done after response */
+ /* 10. Set continueTransSession to FALSE */
+ if (returnCode == TPM_SUCCESS) {
+ continueTransSession = FALSE;
+ }
+ /* 11. Return TPM_SUCCESS */
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ReleaseTransportSigned: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return locality */
+ returnCode = TPM_Sbuffer_Append32(response,
+ tpm_state->tpm_stany_flags.localityModifier);
+ }
+ /* return currentTicks */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CurrentTicks_Store(response, currentTicks);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* return signature */
+ returnCode = TPM_SizedBuffer_Store(response, &signature);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the optional below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ authNonceOdd,
+ continueAuthSession);
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_TransportInternal_Set(response,
+ t1TpmTransportInternal,
+ outParamDigest,
+ transNonceOdd,
+ continueTransSession,
+ TRUE); /* generate transNonceEven */
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueTransSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueTransSession) &&
+ transHandleValid) {
+ TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions,
+ transHandle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&signature); /* @1 */
+ TPM_TransportLogOut_Delete(&a1TransportLogOut); /* @2 */
+ TPM_SignInfo_Delete(&h1SignInfo); /* @3 */
+ return rcf;
+}