summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_session.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tpm12/tpm_session.c5540
1 files changed, 5540 insertions, 0 deletions
diff --git a/src/tpm12/tpm_session.c b/src/tpm12/tpm_session.c
new file mode 100644
index 0000000..da6cbe6
--- /dev/null
+++ b/src/tpm12/tpm_session.c
@@ -0,0 +1,5540 @@
+/********************************************************************************/
+/* */
+/* Session Handler */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: tpm_session.c 4584 2011-06-22 15:49:41Z 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_auth.h"
+#include "tpm_counter.h"
+#include "tpm_crypto.h"
+#include "tpm_cryptoh.h"
+#include "tpm_daa.h"
+#include "tpm_debug.h"
+#include "tpm_delegate.h"
+#include "tpm_digest.h"
+#include "tpm_error.h"
+#include "tpm_init.h"
+#include "tpm_io.h"
+#include "tpm_key.h"
+#include "tpm_nonce.h"
+#include "tpm_nvram.h"
+#include "tpm_pcr.h"
+#include "tpm_process.h"
+#include "tpm_permanent.h"
+#include "tpm_secret.h"
+#include "tpm_transport.h"
+#include "tpm_types.h"
+
+#include "tpm_session.h"
+
+/* local function prototypes */
+
+static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest,
+ TPM_SECRET **authData,
+ TPM_AUTH_SESSION_DATA *authSession,
+ tpm_state_t *tpm_state,
+ uint32_t delegateRowIndex);
+
+static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest);
+static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest);
+static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest);
+static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest);
+static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest);
+static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest);
+
+/*
+ TPM_AUTH_SESSION_DATA (one element of the array)
+*/
+
+/* TPM_AuthSessionData_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_AuthSessionData_Init(TPM_AUTH_SESSION_DATA *tpm_auth_session_data)
+{
+ printf(" TPM_AuthSessionData_Init:\n");
+ tpm_auth_session_data->handle = 0;
+ tpm_auth_session_data->protocolID = 0;
+ tpm_auth_session_data->entityTypeByte = 0;
+ tpm_auth_session_data->adipEncScheme = 0;
+ TPM_Nonce_Init(tpm_auth_session_data->nonceEven);
+ TPM_Secret_Init(tpm_auth_session_data->sharedSecret);
+ TPM_Digest_Init(tpm_auth_session_data->entityDigest);
+ TPM_DelegatePublic_Init(&(tpm_auth_session_data->pub));
+ tpm_auth_session_data->valid = FALSE;
+ return;
+}
+
+/* TPM_AuthSessionData_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_AuthSessionData_Init()
+ After use, call TPM_AuthSessionData_Delete() to free memory
+*/
+
+TPM_RESULT TPM_AuthSessionData_Load(TPM_AUTH_SESSION_DATA *tpm_auth_session_data,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_AuthSessionData_Load:\n");
+ /* load handle */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_auth_session_data->handle), stream, stream_size);
+ }
+ /* load protocolID */
+ if (rc == 0) {
+ rc = TPM_Load16(&(tpm_auth_session_data->protocolID), stream, stream_size);
+ }
+ /* load entityTypeByte */
+ if (rc == 0) {
+ rc = TPM_Loadn(&(tpm_auth_session_data->entityTypeByte), sizeof(BYTE), stream, stream_size);
+ }
+ /* load adipEncScheme */
+ if (rc == 0) {
+ rc = TPM_Loadn(&(tpm_auth_session_data->adipEncScheme), sizeof(BYTE), stream, stream_size);
+ }
+ /* load nonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_auth_session_data->nonceEven, stream, stream_size);
+ }
+ /* load sharedSecret */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_auth_session_data->sharedSecret, stream, stream_size);
+ }
+ /* load entityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_auth_session_data->entityDigest, stream, stream_size);
+ }
+ /* load pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Load(&(tpm_auth_session_data->pub), stream, stream_size);
+ }
+ /* set valid */
+ if (rc == 0) {
+ tpm_auth_session_data->valid = TRUE;
+ }
+ return rc;
+}
+
+/* TPM_AuthSessionData_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_AuthSessionData_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_AUTH_SESSION_DATA *tpm_auth_session_data)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_AuthSessionData_Store:\n");
+ /* store handle */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_auth_session_data->handle);
+ }
+ /* store protocolID */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_auth_session_data->protocolID);
+ }
+ /* store entityTypeByte */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->entityTypeByte), sizeof(BYTE));
+ }
+ /* store adipEncScheme */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->adipEncScheme), sizeof(BYTE));
+ }
+ /* store nonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->nonceEven);
+ }
+ /* store sharedSecret */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->sharedSecret);
+ }
+ /* store entityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_auth_session_data->entityDigest);
+ }
+ /* store pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_auth_session_data->pub));
+ }
+ return rc;
+}
+
+/* TPM_AuthSessionData_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_AuthSessionData_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_AuthSessionData_Delete(TPM_AUTH_SESSION_DATA *tpm_auth_session_data)
+{
+ printf(" TPM_AuthSessionData_Delete:\n");
+ if (tpm_auth_session_data != NULL) {
+ TPM_DelegatePublic_Delete(&(tpm_auth_session_data->pub));
+ TPM_AuthSessionData_Init(tpm_auth_session_data);
+ }
+ return;
+}
+
+/* TPM_AuthSessionData_Copy() copies the source to the destination. The source handle is ignored,
+ since it might already be used.
+*/
+
+void TPM_AuthSessionData_Copy(TPM_AUTH_SESSION_DATA *dest_auth_session_data,
+ TPM_HANDLE tpm_handle,
+ TPM_AUTH_SESSION_DATA *src_auth_session_data)
+{
+ dest_auth_session_data->handle = tpm_handle;
+ dest_auth_session_data->protocolID = src_auth_session_data->protocolID;
+ dest_auth_session_data->entityTypeByte = src_auth_session_data->entityTypeByte;
+ dest_auth_session_data-> adipEncScheme = src_auth_session_data->adipEncScheme;
+ TPM_Nonce_Copy(dest_auth_session_data->nonceEven, src_auth_session_data->nonceEven);
+ TPM_Secret_Copy(dest_auth_session_data->sharedSecret, src_auth_session_data->sharedSecret);
+ TPM_Digest_Copy(dest_auth_session_data->entityDigest, src_auth_session_data->entityDigest);
+ TPM_DelegatePublic_Copy(&(dest_auth_session_data->pub), &(src_auth_session_data->pub));
+ dest_auth_session_data->valid= src_auth_session_data->valid;
+}
+
+/* TPM_AuthSessionData_GetDelegatePublic() */
+
+TPM_RESULT TPM_AuthSessionData_GetDelegatePublic(TPM_DELEGATE_PUBLIC **delegatePublic,
+ TPM_AUTH_SESSION_DATA *auth_session_data)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_AuthSessionData_GetDelegatePublic:\n");
+ if (rc == 0) {
+ *delegatePublic = &(auth_session_data->pub);
+ }
+ return rc;
+}
+
+/* TPM_AuthSessionData_CheckEncScheme() checks that the encryption scheme specified by
+ TPM_ENTITY_TYPE is supported by the TPM (by TPM_AuthSessionData_Decrypt)
+*/
+
+TPM_RESULT TPM_AuthSessionData_CheckEncScheme(TPM_ADIP_ENC_SCHEME adipEncScheme,
+ TPM_BOOL FIPS)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_AuthSessionData_CheckEncScheme: adipEncScheme %02x\n", adipEncScheme);
+ switch (adipEncScheme) {
+ case TPM_ET_XOR:
+ /* i.If TPM_PERMANENT_FLAGS -> FIPS is TRUE */
+ /* (1) All encrypted authorizations MUST use a symmetric key encryption scheme. */
+ if (FIPS) {
+ rc = TPM_INAPPROPRIATE_ENC;
+ }
+ break;
+ case TPM_ET_AES128_CTR:
+ break;
+ default:
+ printf("TPM_AuthSessionData_CheckEncScheme: Error, unsupported adipEncScheme\n");
+ rc = TPM_INAPPROPRIATE_ENC;
+ break;
+ }
+ return rc;
+}
+
+/* TPM_AuthSessionData_Decrypt() decrypts the encAuth secret using the algorithm indicated in the
+ OSAP or DSAP session
+
+ If 'odd' is FALSE, one decrypt of encAuthEven to a1Even.
+ If 'odd' is TRUE, a second decrypt of encAuthOdd to a1Odd is also performed.
+*/
+
+TPM_RESULT TPM_AuthSessionData_Decrypt(TPM_DIGEST a1Even,
+ TPM_DIGEST a1Odd,
+ TPM_ENCAUTH encAuthEven,
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data,
+ TPM_NONCE nonceOdd,
+ TPM_ENCAUTH encAuthOdd,
+ TPM_BOOL odd)
+{
+ TPM_RESULT rc = 0;
+ TPM_DIGEST x1Even;
+ TPM_DIGEST x2Odd;
+
+ printf(" TPM_AuthSessionData_Decrypt:\n");
+ /* sanity check - the session must be OSAP or DSAP */
+ if (rc == 0) {
+ if ((tpm_auth_session_data->protocolID != TPM_PID_OSAP) &&
+ (tpm_auth_session_data->protocolID != TPM_PID_DSAP)) {
+ printf("TPM_AuthSessionData_Decrypt: Error, protocolID should be OSAP, is %04hx\n",
+ tpm_auth_session_data->protocolID);
+ rc = TPM_BAD_MODE;
+ }
+ }
+ if (rc == 0) {
+ /* algorithm indicated in the OSAP session */
+ switch(tpm_auth_session_data->adipEncScheme) {
+ case TPM_ET_XOR:
+ /* 4. If the entity type indicates XOR encryption for the AuthData secret */
+ /* a.Create X1 the SHA-1 of the concatenation of (authHandle -> sharedSecret ||
+ authLastNonceEven). */
+ if (rc == 0) {
+ rc = TPM_SHA1(x1Even,
+ TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret,
+ TPM_NONCE_SIZE, tpm_auth_session_data->nonceEven,
+ 0, NULL);
+ }
+ /* b. Create the decrypted AuthData the XOR of X1 and the encrypted AuthData. */
+ if (rc == 0) {
+ TPM_Digest_XOR(a1Even, encAuthEven, x1Even);
+ }
+ /* c. If the command ordinal contains a second AuthData2 secret
+ (e.g. TPM_CreateWrapKey) */
+ /* i. Create X2 the SHA-1 of the concatenation of (authHandle -> sharedSecret ||
+ nonceOdd). */
+ if ((rc == 0) && (odd)) {
+ rc = TPM_SHA1(x2Odd,
+ TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret,
+ TPM_NONCE_SIZE, nonceOdd,
+ 0, NULL);
+ }
+ /* ii. Create the decrypted AuthData2 the XOR of X2 and the encrypted AuthData2. */
+ if ((rc == 0) && (odd)) {
+ TPM_Digest_XOR(a1Odd, encAuthOdd, x2Odd);
+ }
+ break;
+#ifdef TPM_AES /* if AES is supported */
+ case TPM_ET_AES128_CTR:
+ /* 5. If the entity type indicates symmetric key encryption */
+ /* a. The key for the encryption algorithm is the first bytes of the OSAP shared
+ secret. */
+ /* i. E.g., For AES128, the key is the first 16 bytes of the OSAP shared secret. */
+ /* ii. There is no support for AES keys greater than 128 bits. */
+ /* b. If the entity type indicates CTR mode */
+ /* i. The initial counter value for AuthData is the first bytes of authLastNonceEven. */
+ /* (1) E.g., For AES128, the initial counter value is the first 16 bytes of
+ authLastNonceEven. */
+ /* b. Create the decrypted AuthData from the encrypted AuthData. */
+ if (rc == 0) {
+ rc = TPM_SymmetricKeyData_CtrCrypt(a1Even, /* output data */
+ encAuthEven, /* input data */
+ TPM_AUTHDATA_SIZE, /* data size */
+ tpm_auth_session_data->sharedSecret, /* key */
+ TPM_SECRET_SIZE,
+ tpm_auth_session_data->nonceEven, /* CTR */
+ TPM_NONCE_SIZE);
+ }
+ /* ii. If the command ordinal contains a second AuthData2 secret
+ (e.g. TPM_CreateWrapKey) */
+ /* (1) The initial counter value for AuthData2 is the first bytes of
+ nonceOdd. */
+ /* ii. Create the decrypted AuthData2 from the the encrypted AuthData2. */
+ if ((rc == 0) && (odd)) {
+ rc = TPM_SymmetricKeyData_CtrCrypt(a1Odd, /* output data */
+ encAuthOdd, /* input data */
+ TPM_AUTHDATA_SIZE, /* data size */
+ tpm_auth_session_data->sharedSecret, /* key */
+ TPM_SECRET_SIZE,
+ nonceOdd, /* CTR */
+ TPM_NONCE_SIZE);
+ }
+ /* iii. Additional counter values as required are generated by incrementing the
+ entire counter value as a big endian number. */
+ break;
+#endif /* TPM_AES */
+ default:
+ printf("TPM_AuthSessionData_Decrypt: Error, entityType %02x not supported\n",
+ tpm_auth_session_data->adipEncScheme);
+ rc = TPM_INAPPROPRIATE_ENC;
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_AUTH_SESSION_DATA (the entire array)
+*/
+
+void TPM_AuthSessions_Init(TPM_AUTH_SESSION_DATA *authSessions)
+{
+ size_t i;
+
+ printf(" TPM_AuthSessions_Init:\n");
+ for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ TPM_AuthSessionData_Init(&(authSessions[i]));
+ }
+ return;
+}
+
+/* TPM_AuthSessions_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_AuthSessions_Init()
+*/
+
+TPM_RESULT TPM_AuthSessions_Load(TPM_AUTH_SESSION_DATA *authSessions,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ uint32_t activeCount;
+
+ printf(" TPM_AuthSessions_Load:\n");
+ /* load active count */
+ if (rc == 0) {
+ rc = TPM_Load32(&activeCount, stream, stream_size);
+ }
+ /* load authorization sessions */
+ if (rc == 0) {
+ if (activeCount > TPM_MIN_AUTH_SESSIONS) {
+ printf("TPM_AuthSessions_Load: Error (fatal) %u sessions, %u slots\n",
+ activeCount, TPM_MIN_AUTH_SESSIONS);
+ rc = TPM_FAIL;
+ }
+ }
+ if (rc == 0) {
+ printf(" TPM_AuthSessions_Load: Loading %u sessions\n", activeCount);
+ }
+ for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) {
+ rc = TPM_AuthSessionData_Load(&(authSessions[i]), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_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_AuthSessions_Store(TPM_STORE_BUFFER *sbuffer,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ uint32_t space; /* free authorization session slots */
+ uint32_t activeCount; /* used authorization session slots */
+
+ /* store active count */
+ if (rc == 0) {
+ TPM_AuthSessions_GetSpace(&space, authSessions);
+ activeCount = TPM_MIN_AUTH_SESSIONS - space;
+ printf(" TPM_AuthSessions_Store: Storing %u sessions\n", activeCount);
+ rc = TPM_Sbuffer_Append32(sbuffer, activeCount);
+ }
+ /* store auth sessions */
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) {
+ if ((authSessions[i]).valid) { /* if the session is active */
+ printf(" TPM_AuthSessions_Store: Storing %08x\n", authSessions[i].handle);
+ rc = TPM_AuthSessionData_Store(sbuffer, &(authSessions[i]));
+ }
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_Delete() terminates all sessions
+
+*/
+
+void TPM_AuthSessions_Delete(TPM_AUTH_SESSION_DATA *authSessions)
+{
+ size_t i;
+
+ printf(" TPM_AuthSessions_Delete:\n");
+ for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ TPM_AuthSessionData_Delete(&(authSessions[i]));
+ }
+ return;
+}
+
+/* TPM_AuthSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not.
+
+ If TRUE, 'index' holds the first free position.
+*/
+
+void TPM_AuthSessions_IsSpace(TPM_BOOL *isSpace,
+ uint32_t *index,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ printf(" TPM_AuthSessions_IsSpace:\n");
+ for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_AUTH_SESSIONS ; (*index)++) {
+ if (!((authSessions[*index]).valid)) {
+ printf(" TPM_AuthSessions_IsSpace: Found space at %u\n", *index);
+ *isSpace = TRUE;
+ break;
+ }
+ }
+ return;
+}
+
+void TPM_AuthSessions_Trace(TPM_AUTH_SESSION_DATA *authSessions)
+{
+ size_t i;
+ for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ if ((authSessions[i]).valid) {
+ printf(" TPM_AuthSessions_Trace: %lu handle %08x\n",
+ (unsigned long)i, authSessions[i].handle);
+ }
+ }
+ return;
+}
+
+/* TPM_AuthSessions_GetSpace() returns the number of unused authHandle's.
+
+*/
+
+void TPM_AuthSessions_GetSpace(uint32_t *space,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ uint32_t i;
+
+ printf(" TPM_AuthSessions_GetSpace:\n");
+ for (*space = 0 , i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ if (!((authSessions[i]).valid)) {
+ (*space)++;
+ }
+ }
+ return;
+}
+
+/* TPM_AuthSessions_StoreHandles() stores
+
+ - the number of loaded sessions
+ - a list of session handles
+*/
+
+TPM_RESULT TPM_AuthSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ TPM_RESULT rc = 0;
+ uint16_t i;
+ uint32_t space;
+
+ printf(" TPM_AuthSessions_StoreHandles:\n");
+ /* get the number of loaded handles */
+ if (rc == 0) {
+ TPM_AuthSessions_GetSpace(&space, authSessions);
+ /* store loaded handle count. Cast safe because of TPM_MIN_AUTH_SESSIONS value */
+ rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_AUTH_SESSIONS - space));
+ }
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) {
+ if ((authSessions[i]).valid) { /* if the index is loaded */
+ rc = TPM_Sbuffer_Append32(sbuffer, (authSessions[i]).handle); /* store it */
+ }
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_GetNewHandle() checks for space in the authorization sessions table.
+
+ If there is space, it returns a TPM_AUTH_SESSION_DATA entry in 'tpm_auth_session_data' and its
+ handle in 'authHandle'. The entry is marked 'valid'.
+
+ If *authHandle non-zero, the suggested value is tried first.
+
+ Returns TPM_RESOURCES if there is no space in the sessions table.
+*/
+
+TPM_RESULT TPM_AuthSessions_GetNewHandle(TPM_AUTH_SESSION_DATA **tpm_auth_session_data,
+ TPM_AUTHHANDLE *authHandle,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ TPM_RESULT rc = 0;
+ uint32_t index;
+ TPM_BOOL isSpace;
+
+ printf(" TPM_AuthSessions_GetNewHandle:\n");
+ /* is there an empty entry, get the location index */
+ if (rc == 0) {
+ TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions);
+ if (!isSpace) {
+ printf("TPM_AuthSessions_GetNewHandle: Error, no space in authSessions table\n");
+ TPM_AuthSessions_Trace(authSessions);
+ rc = TPM_RESOURCES;
+ }
+ }
+ if (rc == 0) {
+ rc = TPM_Handle_GenerateHandle(authHandle, /* I/O */
+ authSessions, /* handle array */
+ FALSE, /* keepHandle */
+ FALSE, /* isKeyHandle */
+ (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry);
+ }
+ if (rc == 0) {
+ printf(" TPM_AuthSessions_GetNewHandle: Assigned handle %08x\n", *authHandle);
+ *tpm_auth_session_data = &(authSessions[index]);
+ /* assign the handle */
+ (*tpm_auth_session_data)->handle = *authHandle;
+ (*tpm_auth_session_data)->valid = TRUE;
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_GetEntry() searches all entries for the entry matching the handle, and
+ returns the TPM_AUTH_SESSION_DATA entry associated with the handle.
+
+ Returns
+ 0 for success
+ TPM_INVALID_AUTHHANDLE if the handle is not found
+*/
+
+TPM_RESULT TPM_AuthSessions_GetEntry(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for
+ authHandle */
+ TPM_AUTH_SESSION_DATA *authSessions, /* points to first session
+ */
+ TPM_AUTHHANDLE authHandle) /* input */
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ TPM_BOOL found;
+
+ printf(" TPM_AuthSessions_GetEntry: authHandle %08x\n", authHandle);
+ for (i = 0, found = FALSE ; (i < TPM_MIN_AUTH_SESSIONS) && !found ; i++) {
+ if ((authSessions[i].valid) &&
+ (authSessions[i].handle == authHandle)) { /* found */
+ found = TRUE;
+ *tpm_auth_session_data = &(authSessions[i]);
+ }
+ }
+ if (!found) {
+ printf(" TPM_AuthSessions_GetEntry: session handle %08x not found\n",
+ authHandle);
+ rc = TPM_INVALID_AUTHHANDLE;
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_AddEntry() adds an TPM_AUTH_SESSION_DATA 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_AuthSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */
+ TPM_BOOL keepHandle, /* input */
+ TPM_AUTH_SESSION_DATA *authSessions, /* input */
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data) /* input */
+{
+ TPM_RESULT rc = 0;
+ uint32_t index;
+ TPM_BOOL isSpace;
+
+ printf(" TPM_AuthSessions_AddEntry: handle %08x, keepHandle %u\n",
+ *tpm_handle, keepHandle);
+ /* check for valid TPM_AUTH_SESSION_DATA */
+ if (rc == 0) {
+ if (tpm_auth_session_data == NULL) { /* NOTE: should never occur */
+ printf("TPM_AuthSessions_AddEntry: Error (fatal), NULL TPM_AUTH_SESSION_DATA\n");
+ rc = TPM_FAIL;
+ }
+ }
+ /* is there an empty entry, get the location index */
+ if (rc == 0) {
+ TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions);
+ if (!isSpace) {
+ printf("TPM_AuthSessions_AddEntry: Error, session entries full\n");
+ TPM_AuthSessions_Trace(authSessions);
+ rc = TPM_RESOURCES;
+ }
+ }
+ if (rc == 0) {
+ rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */
+ authSessions, /* handle array */
+ keepHandle, /* keepHandle */
+ FALSE, /* isKeyHandle */
+ (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry);
+ }
+ if (rc == 0) {
+ TPM_AuthSessionData_Copy(&(authSessions[index]), *tpm_handle, tpm_auth_session_data);
+ authSessions[index].valid = TRUE;
+ printf(" TPM_AuthSessions_AddEntry: Index %u handle %08x\n",
+ index, authSessions[index].handle);
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_GetData() checks that authHandle indexes a valid TPM_AUTH_SESSION_DATA object.
+ If so, a pointer to the object is returned in tpm_auth_session_data.
+
+ If required protocolID is either TPM_PID_OIAP or TPM_PID_OSAP, the object is checked for that
+ type. TPM_PID_OSAP will accept DSAP as well. If it is TPM_PID_NONE, either is accepted. Any
+ other value is unsupported.
+
+ If the session protocolID is OIAP, the input entityAuth is echoed back as the HMAC key.
+ entityDigest is ignored and may be NULL.
+
+ If the session protocolID is OSAP or DSAP, the function must check that the entity used to set up
+ the session is the same as the entity specified in the processing command. It does that by
+ comparing the entityDigest to that saved during setup of the OSAP session. The shared secret is
+ returned as the HMAC key. entityAuth is ignored and may be NULL.
+
+ If the session protocolID is DSAP, the TPM_DELEGATE_PUBLIC saved during the TPM_DSAP session
+ setup is checked for permission and PCR's. The entityType (TPM_ET_KEYHANDLE or TPM_ET_OWNER) is
+ checked against the TPM_DELEGATE_PUBLIC -> TPM_DELEGATIONS delegateType. Then the bit map is
+ fetched from the ordinals table and verified against the per1 or per 2 values. The pcrInfo is
+ checked against the current PCR values.
+
+ The saved entityDigest depends upon the entity type:
+
+ TPM_ET_KEYHANDLE: pubDataDigest
+ TPM_ET_OWNER: ownerAuth
+ TPM_ET_SRK: TPM_KEY -> key_digest
+ TPM_ET_COUNTER: TPM_COUNTER_VALUE -> digest
+ TPM_ET_NV: TPM_NV_DATA_SENSITIVE -> digest
+*/
+
+TPM_RESULT TPM_AuthSessions_GetData(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for
+ authHandle */
+ TPM_SECRET **hmacKey, /* output */
+ tpm_state_t *tpm_state, /* input */
+ TPM_AUTHHANDLE authHandle, /* input */
+ TPM_PROTOCOL_ID protocolID, /* input: required protocol */
+ TPM_ENT_TYPE entityType, /* input: entity type */
+ TPM_COMMAND_CODE ordinal, /* input: for delegation */
+ TPM_KEY *tpmKey, /* input, for delegate restrictions */
+ TPM_SECRET *entityAuth, /* input OIAP hmac key */
+ TPM_DIGEST entityDigest) /* input OSAP session setup auth */
+{
+ TPM_RESULT rc = 0;
+ TPM_DELEGATE_TABLE_ROW *delegateTableRow;
+
+ printf(" TPM_AuthSessions_GetData: authHandle %08x\n", authHandle);
+ if (rc == 0) {
+ rc = TPM_AuthSessions_GetEntry(tpm_auth_session_data,
+ tpm_state->tpm_stclear_data.authSessions,
+ authHandle);
+ if (rc != 0) {
+ printf("TPM_AuthSessions_GetData: Error, authHandle %08x not found\n", authHandle);
+ }
+ }
+ /* If a specific protocol is required, check that the handle points to the correct session type
+ */
+ if (rc == 0) {
+ switch (protocolID) { /* what protocol is required */
+ case TPM_PID_NONE: /* accept any protocol */
+ break;
+ case TPM_PID_OIAP:
+ if ((*tpm_auth_session_data)->protocolID != TPM_PID_OIAP) {
+ printf("TPM_AuthSessions_GetData: Error, "
+ "session protocolID should be OIAP, is %04hx\n",
+ (*tpm_auth_session_data)->protocolID);
+ rc = TPM_BAD_MODE;
+ }
+ break;
+ case TPM_PID_OSAP:
+ /* Any ordinal requiring OSAP should also accept DSAP */
+ if (((*tpm_auth_session_data)->protocolID != TPM_PID_OSAP) &&
+ ((*tpm_auth_session_data)->protocolID != TPM_PID_DSAP)) {
+ printf("TPM_AuthSessions_GetData: Error, "
+ "session protocolID should be OSAP or DSAP, is %04hx\n",
+ (*tpm_auth_session_data)->protocolID);
+ rc = TPM_BAD_MODE;
+ }
+ break;
+ default: /* should not occur */
+ printf("TPM_AuthSessions_GetData: Error, required protocolID %04hx unsupported\n",
+ protocolID);
+ rc = TPM_BAD_MODE;
+ break;
+ }
+ }
+ /* if the entity is owner auth, verify that an owner is installed */
+ if (rc == 0) {
+ if (entityType == TPM_ET_OWNER) {
+ if (!tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_AuthSessions_GetData: Error, no owner installed\n");
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ }
+ /* session protocol specific processing */
+ if (rc == 0) {
+ switch ((*tpm_auth_session_data)->protocolID) {
+ case TPM_PID_OIAP:
+ /* a. If the command using the OIAP session requires owner authorization */
+ /* i. If TPM_STCLEAR_DATA -> ownerReference is TPM_KH_OWNER, the secret AuthData is
+ TPM_PERMANENT_DATA -> ownerAuth */
+ /* ii. If TPM_STCLEAR_DATA -> ownerReference is pointing to a delegate row */
+ if ((entityType == TPM_ET_OWNER) &&
+ (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) {
+ printf(" TPM_AuthSessions_GetData: Delegating to row %u\n",
+ tpm_state->tpm_stclear_data.ownerReference);
+ /* (1) Set R1 a row index to TPM_STCLEAR_DATA -> ownerReference */
+ /* (2) Set D1 a TPM_DELEGATE_TABLE_ROW to TPM_PERMANENT_DATA -> delegateTable ->
+ delRow[R1] */
+ if (rc == 0) {
+ rc = TPM_DelegateTable_GetValidRow
+ (&delegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ tpm_state->tpm_stclear_data.ownerReference);
+ }
+ /* (4) Validate the TPM_DELEGATE_PUBLIC D1 -> pub based on the command ordinal */
+ /* (a) Validate D1 -> pub -> permissions based on the command ordinal */
+ /* (b) Validate D1 -> pub -> pcrInfo based on the PCR values */
+ if (rc == 0) {
+ rc = TPM_Delegations_CheckPermission(tpm_state,
+ &(delegateTableRow->pub),
+ entityType,
+ ordinal);
+ }
+ /* (3) Set the secret AuthData to D1 -> authValue */
+ if (rc == 0) {
+ *hmacKey = &(delegateTableRow->authValue);
+ }
+ }
+ /* not owner or owner but not delegated */
+ else {
+ /* the hmac key is the input authorization secret */
+ *hmacKey = entityAuth;
+ }
+ break;
+ case TPM_PID_OSAP:
+ case TPM_PID_DSAP: /* the first part of DSAP is the same as OSAP */
+ /* ensure that the OSAP shared secret is that derived from the entity using OSAP */
+ if (rc == 0) {
+ rc = TPM_Digest_Compare(entityDigest, (*tpm_auth_session_data)->entityDigest);
+ }
+ /* extra processing for DSAP sessions */
+ if ((*tpm_auth_session_data)->protocolID == TPM_PID_DSAP) {
+ /* check that delegation is allowed for the ordinal */
+ if (rc == 0) {
+ rc = TPM_Delegations_CheckPermission(tpm_state,
+ &((*tpm_auth_session_data)->pub),
+ entityType, /* required for ordinal */
+ ordinal);
+ }
+ /* check restrictions on delegation of a certified migration key */
+ if ((rc == 0) && (entityType == TPM_ET_KEYHANDLE)) {
+ rc = TPM_Key_CheckRestrictDelegate
+ (tpmKey,
+ tpm_state->tpm_permanent_data.restrictDelegate);
+ }
+ }
+ /* the HMAC key is the shared secret calculated during OSAP setup */
+ if (rc == 0) {
+ *hmacKey = &((*tpm_auth_session_data)->sharedSecret);
+ }
+ break;
+ default: /* should not occur */
+ printf("TPM_AuthSessions_GetData: session protocolID %04hx unsupported\n",
+ (*tpm_auth_session_data)->protocolID);
+ rc = TPM_AUTHFAIL;
+ break;
+ }
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_TerminateHandle() terminates the session associated with 'authHandle'.
+
+*/
+
+TPM_RESULT TPM_AuthSessions_TerminateHandle(TPM_AUTH_SESSION_DATA *authSessions,
+ TPM_AUTHHANDLE authHandle)
+{
+ TPM_RESULT rc = 0;
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data;
+
+ printf(" TPM_AuthSessions_TerminateHandle: Handle %08x\n", authHandle);
+ /* get the TPM_AUTH_SESSION_DATA associated with the TPM_AUTHHANDLE */
+ if (rc == 0) {
+ rc = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, authSessions, authHandle);
+ }
+ /* invalidate the valid handle */
+ if (rc == 0) {
+ TPM_AuthSessionData_Delete(tpm_auth_session_data);
+ }
+ return rc;
+}
+
+/* TPM_AuthSessions_TerminateEntity() terminates all OSAP and DSAP sessions connected to the
+ entityType.
+
+ If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for
+ the ordinal response.
+
+ If the entityDigest is NULL, all sessions are terminated. If entityDigest is not NULL, only
+ those with a matching entityDigest are terminated.
+ */
+
+void TPM_AuthSessions_TerminateEntity(TPM_BOOL *continueAuthSession,
+ TPM_AUTHHANDLE authHandle,
+ TPM_AUTH_SESSION_DATA *authSessions,
+ TPM_ENT_TYPE entityType,
+ TPM_DIGEST *entityDigest)
+{
+ uint32_t i;
+ TPM_BOOL terminate;
+ TPM_RESULT match;
+
+ printf(" TPM_AuthSessions_TerminateEntity: entityType %04x\n", entityType);
+ for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ terminate = FALSE;
+ if ((authSessions[i].valid) && /* if the entry is valid */
+ ((authSessions[i].protocolID == TPM_PID_OSAP) || /* if it's OSAP or DSAP */
+ (authSessions[i].protocolID == TPM_PID_DSAP)) &&
+ (authSessions[i].entityTypeByte == entityType)) { /* connected to entity type */
+ /* if entityDigest is NULL, terminate all matching entityType */
+ if (entityDigest == NULL) {
+ terminate = TRUE;
+ }
+ /* if entityDigest is not NULL, terminate only those matching entityDigest */
+ else {
+ match = TPM_Digest_Compare(*entityDigest, authSessions[i].entityDigest);
+ if (match == 0) {
+ terminate = TRUE;
+ }
+ }
+ }
+ if (terminate) {
+ printf(" TPM_AuthSessions_TerminateEntity: Terminating handle %08x\n",
+ authSessions[i].handle);
+ /* if terminating the ordinal's session */
+ if (authSessions[i].handle == authHandle) {
+ *continueAuthSession = FALSE; /* for the ordinal response */
+ }
+ TPM_AuthSessionData_Delete(&authSessions[i]);
+ }
+ }
+ return;
+}
+
+/* TPM_AuthSessions_TerminatexSAP terminates all OSAP and DSAP sessions
+
+ If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for
+ the ordinal response.
+
+ It is safe to call this function during ordinal processing provided a copy of the shared secret
+ is first saved for the response HMAC calculation.
+
+ The evenNonce is newly created for the response. The oddNonce and continueAuthSession are
+ command inputs, not part of the session data structure.
+*/
+
+void TPM_AuthSessions_TerminatexSAP(TPM_BOOL *continueAuthSession,
+ TPM_AUTHHANDLE authHandle,
+ TPM_AUTH_SESSION_DATA *authSessions)
+{
+ uint32_t i;
+
+ printf(" TPM_AuthSessions_TerminatexSAP:\n");
+ for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) {
+ if ((authSessions[i].protocolID == TPM_PID_OSAP) ||
+ (authSessions[i]. protocolID == TPM_PID_DSAP)) {
+ /* if terminating the ordinal's session */
+ if (authSessions[i].handle == authHandle) {
+ *continueAuthSession = FALSE; /* for the ordinal response */
+ }
+ printf(" TPM_AuthSessions_TerminatexSAP: Terminating handle %08x\n",
+ authSessions[i].handle);
+ TPM_AuthSessionData_Delete(&authSessions[i]);
+ }
+ }
+ return;
+}
+
+/*
+ Context List
+
+ Methods to manipulate the TPM_STANY_DATA->contextList[TPM_MAX_SESSION_LIST] array
+*/
+
+/* TPM_ContextList_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_ContextList_Init(uint32_t *contextList)
+{
+ size_t i;
+
+ printf(" TPM_ContextList_Init:\n");
+ for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) {
+ contextList[i] = 0;
+ }
+ return;
+}
+
+/* TPM_ContextList_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_ContextList_Init()
+*/
+
+TPM_RESULT TPM_ContextList_Load(uint32_t *contextList,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_ContextList_Load:\n");
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) {
+ rc = TPM_Load32(&(contextList[i]), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_ContextList_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_ContextList_Store(TPM_STORE_BUFFER *sbuffer,
+ const uint32_t *contextList)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_ContextList_Store: Storing %u contexts\n", TPM_MIN_SESSION_LIST);
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) {
+ rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]);
+ }
+ return rc;
+}
+
+/* TPM_ContextList_GetSpace() returns 'space', the number of unused context list entries.
+
+ If 'space' is non-zero, 'entry' points to the first unused index.
+*/
+
+void TPM_ContextList_GetSpace(uint32_t *space,
+ uint32_t *entry,
+ const uint32_t *contextList)
+{
+ uint32_t i;
+
+ printf(" TPM_ContextList_GetSpace:\n");
+ for (*space = 0 , i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) {
+ if (contextList[i] == 0) { /* zero values are free space */
+ if (*space == 0) {
+ *entry = i; /* point to the first non-zero entry */
+ }
+ (*space)++;
+ }
+ }
+ return;
+}
+
+/* TPM_ContextList_GetEntry() gets the entry index corresponding to the value
+
+*/
+
+TPM_RESULT TPM_ContextList_GetEntry(uint32_t *entry,
+ const uint32_t *contextList,
+ uint32_t value)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ContextList_GetEntry:\n");
+ if (rc == 0) {
+ if (value == 0) {
+ printf("TPM_ContextList_GetEntry: Error, value %d never found\n", value);
+ rc = TPM_BADCONTEXT;
+ }
+ }
+ if (rc == 0) {
+ for (*entry = 0 ; *entry < TPM_MIN_SESSION_LIST ; (*entry)++) {
+ if (contextList[*entry] == value) {
+ break;
+ }
+ }
+ if (*entry == TPM_MIN_SESSION_LIST) {
+ printf("TPM_ContextList_GetEntry: Error, value %d not found\n", value);
+ rc = TPM_BADCONTEXT;
+ }
+ }
+ return rc;
+}
+
+/* TPM_ContextList_StoreHandles() stores
+
+ - the number of loaded context entries
+ - a list of context handles
+*/
+
+TPM_RESULT TPM_ContextList_StoreHandles(TPM_STORE_BUFFER *sbuffer,
+ const uint32_t *contextList)
+{
+ TPM_RESULT rc = 0;
+ uint16_t i;
+ uint16_t loaded;
+
+ printf(" TPM_ContextList_StoreHandles:\n");
+ if (rc == 0) {
+ loaded = 0;
+ /* count the number of loaded handles */
+ for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) {
+ if (contextList[i] != 0) {
+ loaded++;
+ }
+ }
+ /* store 'loaded' handle count */
+ rc = TPM_Sbuffer_Append16(sbuffer, loaded);
+ }
+ for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST ) ; i++) {
+ if (contextList[i] != 0) { /* if the index is loaded */
+ rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]); /* store it */
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_CONTEXT_BLOB
+*/
+
+/* TPM_ContextBlob_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_ContextBlob_Init(TPM_CONTEXT_BLOB *tpm_context_blob)
+{
+ printf(" TPM_ContextBlob_Init:\n");
+ tpm_context_blob->resourceType = 0;
+ tpm_context_blob->handle = 0;
+ memset(tpm_context_blob->label, 0, TPM_CONTEXT_LABEL_SIZE);
+ tpm_context_blob->contextCount = 0;
+ TPM_Digest_Init(tpm_context_blob->integrityDigest);
+ TPM_SizedBuffer_Init(&(tpm_context_blob->additionalData));
+ TPM_SizedBuffer_Init(&(tpm_context_blob->sensitiveData));
+ return;
+}
+
+/* TPM_ContextBlob_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_ContextBlob_Init()
+ After use, call TPM_ContextBlob_Delete() to free memory
+*/
+
+TPM_RESULT TPM_ContextBlob_Load(TPM_CONTEXT_BLOB *tpm_context_blob,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ContextBlob_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_CONTEXTBLOB, stream, stream_size);
+ }
+ /* load resourceType */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_context_blob->resourceType), stream, stream_size);
+ }
+ /* load handle */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_context_blob->handle), stream, stream_size);
+ }
+ /* load label */
+ if (rc == 0) {
+ rc = TPM_Loadn(tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE, stream, stream_size);
+ }
+ /* load contextCount */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_context_blob->contextCount), stream, stream_size);
+ }
+ /* load integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_context_blob->integrityDigest, stream, stream_size);
+ }
+ /* load additionalData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_context_blob->additionalData), stream, stream_size);
+ }
+ /* load sensitiveData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_context_blob->sensitiveData), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_ContextBlob_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_ContextBlob_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_CONTEXT_BLOB *tpm_context_blob)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ContextBlob_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXTBLOB);
+ }
+ /* store resourceType */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->resourceType);
+ }
+ /* store handle */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->handle);
+ }
+ /* store label */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE);
+ }
+ /* store contextCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->contextCount);
+ }
+ /* store integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_context_blob->integrityDigest);
+ }
+ /* store additionalData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->additionalData));
+ }
+ /* store sensitiveData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->sensitiveData));
+ }
+ return rc;
+}
+
+/* TPM_ContextBlob_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_ContextBlob_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_ContextBlob_Delete(TPM_CONTEXT_BLOB *tpm_context_blob)
+{
+ printf(" TPM_ContextBlob_Delete:\n");
+ if (tpm_context_blob != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_context_blob->additionalData));
+ TPM_SizedBuffer_Delete(&(tpm_context_blob->sensitiveData));
+ TPM_ContextBlob_Init(tpm_context_blob);
+ }
+ return;
+}
+
+/*
+ TPM_CONTEXT_SENSITIVE
+*/
+
+/* TPM_ContextSensitive_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_ContextSensitive_Init(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive)
+{
+ printf(" TPM_ContextSensitive_Init:\n");
+ TPM_Nonce_Init(tpm_context_sensitive->contextNonce);
+ TPM_SizedBuffer_Init(&(tpm_context_sensitive->internalData));
+ return;
+}
+
+/* TPM_ContextSensitive_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_ContextSensitive_Init()
+ After use, call TPM_ContextSensitive_Delete() to free memory
+*/
+
+TPM_RESULT TPM_ContextSensitive_Load(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ContextSensitive_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_CONTEXT_SENSITIVE, stream, stream_size);
+ }
+ /* load contextNonce */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_context_sensitive->contextNonce, stream, stream_size);
+ }
+ /* load internalData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_context_sensitive->internalData), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_ContextSensitive_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_ContextSensitive_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_CONTEXT_SENSITIVE *tpm_context_sensitive)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ContextSensitive_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXT_SENSITIVE);
+ }
+ /* store contextNonce */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(sbuffer, tpm_context_sensitive->contextNonce);
+ }
+ /* store internalData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_sensitive->internalData));
+ }
+ return rc;
+}
+
+/* TPM_ContextSensitive_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_ContextSensitive_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_ContextSensitive_Delete(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive)
+{
+ printf(" TPM_ContextSensitive_Delete:\n");
+ if (tpm_context_sensitive != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_context_sensitive->internalData));
+ TPM_ContextSensitive_Init(tpm_context_sensitive);
+ }
+ return;
+}
+
+/*
+ Processing Functions
+*/
+
+
+/* 18.1 TPM_OIAP rev 87
+
+*/
+
+TPM_RESULT TPM_Process_OIAP(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 */
+
+ /* 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_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */
+ TPM_BOOL got_handle = FALSE;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_AUTHHANDLE authHandle = 0; /* 0, no suggested value */
+
+ printf("TPM_Process_OIAP: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* 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_NOT_SHUTDOWN |
+ TPM_CHECK_NO_LOCKOUT));
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_OIAP: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM_OIAP command allows the creation of an authorization session handle and the
+ tracking of the handle by the TPM. The TPM generates the handle and nonce. */
+ /* 2. The TPM has an internal limit as to the number of handles that may be open at one time, so
+ the request for a new handle may fail if there is insufficient space available. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetNewHandle(&authSession,
+ &authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ }
+ /* 3. Internally the TPM will do the following: */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OIAP: Using authHandle %08x\n", authHandle);
+ got_handle = TRUE;
+ /* a. TPM allocates space to save handle, protocol identification, both nonces and any other
+ information the TPM needs to manage the session. */
+ authSession->protocolID = TPM_PID_OIAP;
+ /* b. TPM generates authHandle and nonceEven, returns these to caller */
+ returnCode = TPM_Nonce_Generate(authSession->nonceEven);
+ }
+ /* 4. On each subsequent use of the OIAP session the TPM MUST generate a new nonceEven value. */
+ /* 5. When TPM_OIAP is wrapped in an encrypted transport session no input or output
+ parameters encrypted */
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_OIAP: 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;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ /* append authHandle */
+ returnCode = TPM_Sbuffer_Append32(response, authHandle);
+ }
+ /* append nonceEven */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, authSession->nonceEven);
+ }
+ /* 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 */
+ }
+ /* 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 the handle is not being returned, it should be terminated */
+ if (((returnCode != 0) || (rcf != 0)) && got_handle) {
+ TPM_AuthSessionData_Delete(authSession);
+ }
+ return rcf;
+}
+
+/* 18.2 TPM_OSAP rev 98
+
+ The TPM_OSAP command creates the authorization handle, the shared secret and generates nonceEven
+ and nonceEvenOSAP.
+
+ 1 The TPM_OSAP command allows the creation of an authorization handle and the tracking of the
+ handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP.
+
+ 2. The TPM has an internal limit on the number of handles that may be open at one time, so the
+ request for a new handle may fail if there is insufficient space available.
+
+ 3. The TPM_OSAP allows the binding of an authorization to a specific entity. This allows the
+ caller to continue to send in authorization data for each command but not have to request the
+ information or cache the actual authorization data.
+
+ 4. When TPM_OSAP is wrapped in an encrypted transport session, no input or output parameters are
+ encrypted
+
+ 5. If the owner pointer is pointing to a delegate row, the TPM internally MUST treat the OSAP
+ session as a DSAP session
+
+ 6. TPM_ET_SRK or TPM_ET_KEYHANDLE with a value of TPM_KH_SRK MUST specify the SRK.
+
+ 7. If the entity is tied to PCR values, the PCR's are not validated during the TPM_OSAP ordinal
+ session creation. The PCR's are validated when the OSAP session is used.
+*/
+
+TPM_RESULT TPM_Process_OSAP(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_ENTITY_TYPE entityType; /* The type of entity in use */
+ uint32_t entityValue = 0; /* The selection value based on entityType, e.g. a
+ keyHandle # */
+ TPM_NONCE nonceOddOSAP; /* The nonce generated by the caller associated with
+ the shared secret. */
+ /* 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_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */
+ TPM_BOOL got_handle = FALSE;
+ TPM_SECRET *authData; /* usageAuth for the entity */
+ TPM_DIGEST *entityDigest = NULL; /* digest of the entity establishing the OSAP
+ session, initialize to silence compiler */
+ TPM_KEY *authKey; /* key to authorize */
+ TPM_BOOL parentPCRStatus;
+ TPM_COUNTER_VALUE *counterValue; /* associated with entityValue */
+ TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization
+ state. */
+ TPM_NONCE nonceEvenOSAP; /* Nonce generated by TPM and associated with shared
+ secret. */
+
+ printf("TPM_Process_OSAP: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* get entityType */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get entityValue */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&entityValue, &command, &paramSize);
+ }
+ /* get nonceOddOSAP */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityValue %08x\n", entityValue);
+ returnCode = TPM_Nonce_Load(nonceOddOSAP, &command, &paramSize);
+ }
+ /* 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_NOT_SHUTDOWN |
+ TPM_CHECK_OWNER |
+ TPM_CHECK_NO_LOCKOUT));
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_OSAP: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM creates S1 a storage area that keeps track of the information associated with the
+ authorization. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetNewHandle(&authSession,
+ &authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: Using authHandle %08x\n", authHandle);
+ got_handle = TRUE;
+ /* 2. S1 MUST track the following information: */
+ /* a. Protocol identification */
+ authSession->protocolID = TPM_PID_OSAP; /* save protocol identification */
+ authSession->entityTypeByte = entityType & 0x00ff; /* save entity type LSB */
+ /* b. nonceEven */
+ /* i. Initialized to the next value from the TPM RNG */
+ TPM_Nonce_Generate(authSession->nonceEven);
+ /* c. shared secret NOTE: determined below */
+ /* d. ADIP encryption scheme from TPM_ENTITY_TYPE entityType */
+ authSession->adipEncScheme = (entityType >> 8) & 0x00ff; /* save entity type MSB */
+ /* e. Any other internal TPM state the TPM needs to manage the session */
+ /* 3. The TPM MUST create and MAY track the following information */
+ /* a. nonceEvenOSAP */
+ /* i. Initialized to the next value from the TPM RNG */
+ TPM_Nonce_Generate(nonceEvenOSAP);
+ /* 4. HMAC, shared secret NOTE: determined below */
+ /* 5. Check if the ADIP encryption scheme specified by entityType is supported, if not
+ return TPM_INAPPROPRIATE_ENC. */
+ returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme,
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ switch (authSession->entityTypeByte) {
+ case TPM_ET_KEYHANDLE:
+ /* 6. If entityType = TPM_ET_KEYHANDLE */
+ /* a. The entity to authorize is a key held in the TPM. entityValue contains the
+ keyHandle that holds the key. */
+ /* b. If entityValue is TPM_KH_OPERATOR return TPM_BAD_HANDLE */
+ if (returnCode == TPM_SUCCESS) {
+ if (entityValue == TPM_KH_OPERATOR) {
+ printf("TPM_Process_OSAP: Error, "
+ "entityType TPM_ET_KEYHANDLE entityValue TPM_KH_OPERATOR\n");
+ returnCode = TPM_BAD_HANDLE;
+ }
+ }
+ /* look up and get the TPM_KEY authorization data */
+ if (returnCode == TPM_SUCCESS) {
+ /* get the TPM_KEY, entityValue is the handle */
+ printf("TPM_Process_OSAP: entityType TPM_ET_KEYHANDLE entityValue %08x\n",
+ entityValue);
+ /* TPM_KeyHandleEntries_GetKey() does the mapping from TPM_KH_SRK to the SRK */
+ returnCode = TPM_KeyHandleEntries_GetKey(&authKey,
+ &parentPCRStatus,
+ tpm_state,
+ entityValue,
+ TRUE, /* read only */
+ TRUE, /* ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the entityDigest for the key */
+ entityDigest = &(authKey->tpm_store_asymkey->pubDataDigest);
+ /* get the usageAuth for the key */
+ returnCode = TPM_Key_GetUsageAuth(&authData, authKey);
+ }
+ break;
+ case TPM_ET_OWNER:
+ /* 7. else if entityType = TPM_ET_OWNER */
+ /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */
+ /* b. The HMAC key is the secret pointed to by ownerReference (owner secret or delegated
+ secret) */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityType TPM_ET_OWNER, ownerReference %08x\n",
+ tpm_state->tpm_stclear_data.ownerReference);
+ /* verify that an owner is installed */
+ if (!tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_Process_OSAP: Error, no owner\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* owner reference is owner, use the owner authorization data */
+ if (tpm_state->tpm_stclear_data.ownerReference == TPM_KH_OWNER) {
+ entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth);
+ authData = &(tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ /* Description 5. If the owner pointer is pointing to a delegate row, the TPM
+ internally MUST treat the OSAP session as a DSAP session */
+ else {
+ returnCode = TPM_OSAPDelegate(&entityDigest,
+ &authData,
+ authSession,
+ tpm_state,
+ tpm_state->tpm_stclear_data.ownerReference);
+ }
+ }
+ break;
+ case TPM_ET_SRK:
+ /* 8. else if entityType = TPM_ET_SRK */
+ /* a. The entity to authorize is the SRK. entityValue is ignored. */
+ printf("TPM_Process_OSAP: entityType TPM_ET_SRK\n");
+ entityDigest = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest);
+ returnCode = TPM_Key_GetUsageAuth(&authData, &(tpm_state->tpm_permanent_data.srk));
+ break;
+ case TPM_ET_COUNTER:
+ /* 9. else if entityType = TPM_ET_COUNTER */
+ /* a. The entity is a monotonic counter, entityValue contains the counter handle */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityType TPM_ET_COUNTER entityValue %08x\n",
+ entityValue);
+ returnCode =
+ TPM_Counters_GetCounterValue(&counterValue,
+ tpm_state->tpm_permanent_data.monotonicCounter,
+ entityValue);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the entityDigest for the counter */
+ entityDigest = &(counterValue->digest);
+ /* get the authData for the counter */
+ authData = &(counterValue->authData);
+ }
+ break;
+ case TPM_ET_NV:
+ /* 10. else if entityType = TPM_ET_NV
+ a. The entity is a NV index, entityValue contains the NV index */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityType TPM_ET_NV\n");
+ returnCode = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive,
+ &(tpm_state->tpm_nv_index_entries),
+ entityValue);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the entityDigest for the NV data */
+ entityDigest = &(tpm_nv_data_sensitive->digest);
+ /* get the authData for the NV data */
+ authData = &(tpm_nv_data_sensitive->authValue);
+ }
+ break;
+ default:
+ /* 11. else return TPM_INVALID_PARAMETER */
+ printf("TPM_Process_OSAP: Error, unknown entityType %04x\n", entityType);
+ returnCode = TPM_BAD_PARAMETER;
+ break;
+ }
+ }
+ /* 2.c. shared secret */
+ /* 4. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC
+ calculation is the secret AuthData assigned to the key handle identified by entityValue.
+ The input to the HMAC calculation is the concatenation of nonces nonceEvenOSAP and
+ nonceOddOSAP. The output of the HMAC calculation is the shared secret which is saved in
+ the authorization area associated with authHandle */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_Digest_Copy(authSession->entityDigest, *entityDigest);
+ TPM_PrintFour("TPM_Process_OSAP: entityDigest", *entityDigest);
+ TPM_PrintFour("TPM_Process_OSAP: authData", *authData);
+ TPM_PrintFour("TPM_Process_OSAP: nonceEvenOSAP", nonceEvenOSAP);
+ TPM_PrintFour("TPM_Process_OSAP: nonceOddOSAP", nonceOddOSAP);
+ returnCode = TPM_HMAC_Generate(authSession->sharedSecret,
+ *authData, /* HMAC key */
+ TPM_NONCE_SIZE, nonceEvenOSAP,
+ TPM_NONCE_SIZE, nonceOddOSAP,
+ 0, NULL);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_OSAP: sharedSecret", authSession->sharedSecret);
+ }
+ /* 12. On each subsequent use of the OSAP session the TPM MUST generate a new nonce value.
+ NOTE: Done as the response is generated. */
+ /* 13. The TPM MUST ensure that OSAP shared secret is only available while the OSAP session is
+ valid.
+ */
+ /* 14. The session MUST terminate upon any of the following conditions:
+ a. The command that uses the session returns an error
+ NOTE Done by command
+ b. The resource is evicted from the TPM or otherwise invalidated
+ NOTE Done by evict or flush
+ c. The session is used in any command for which the shared secret is used to encrypt an
+ input parameter (TPM_ENCAUTH)
+ NOTE Done by the command
+ d. The TPM Owner is cleared
+ NOTE Done by owner clear
+ e. TPM_ChangeAuthOwner is executed and this session is attached to the owner authorization
+ NOTE Done by TPM_ChangeAuthOwner
+ f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific
+ NOTE Done by the ordinal processing
+ g. All OSAP sessions associated with the delegation table MUST be invalidated when any of the
+ following commands execute:
+ i. TPM_Delegate_Manage
+ ii. TPM_Delegate_CreateOwnerDelegation with Increment==TRUE
+ iii. TPM_Delegate_LoadOwnerDelegation
+ NOTE Done by the ordinal processing
+ */
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_OSAP: 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;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ /* append authHandle */
+ returnCode = TPM_Sbuffer_Append32(response, authHandle);
+ }
+ /* append nonceEven */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, authSession->nonceEven);
+ }
+ /* append nonceEvenOSAP */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, nonceEvenOSAP);
+ }
+ /* 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 */
+ }
+ /* 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 the handle is not being returned, it should be terminated */
+ if (((returnCode != 0) || (rcf != 0)) && got_handle) {
+ TPM_AuthSessionData_Delete(authSession);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 18.3 TPM_DSAP rev 106
+
+ The TPM_DSAP command creates the authorization session handle using a delegated AuthData value
+ passed into the command as an encrypted blob or from the internal delegation table. It can be
+ used to start an authorization session for a user key or the owner.
+
+ As in TPM_OSAP, it generates a shared secret and generates nonceEven and nonceEvenOSAP.
+
+ 1. The TPM_DSAP command allows the creation of an authorization session handle and the tracking
+ of the handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP.
+
+ 2. The TPM has an internal limit on the number of handles that may be open at one time, so the
+ request for a new handle may fail if there is insufficient space available.
+
+ 3. The TPM_DSAP allows the binding of a delegated authorization to a specific entity. This allows
+ the caller to continue to send in AuthData for each command but not have to request the
+ information or cache the actual AuthData.
+
+ 4. On each subsequent use of the DSAP session the TPM MUST generate a new nonce value and check if
+ the ordinal to be executed has delegation to execute. The TPM MUST ensure that the DSAP shared
+ secret is only available while the DSAP session is valid.
+
+ 5. When TPM_DSAP is wrapped in an encrypted transport session
+ a. For input the only parameter encrypted or logged is entityValue
+ b. For output no parameters are encrypted or logged
+
+ 6. The DSAP session MUST terminate under any of the following conditions
+
+ a. The command that uses the session returns an error
+ b. If attached to a key, when the key is evicted from the TPM or otherwise invalidated
+ c. The session is used in any command for which the shared secret is used to encrypt an
+ input parameter (TPM_ENCAUTH)
+ d. The TPM Owner is cleared
+ e. TPM_ChangeAuthOwner is executed and this session is attached to the owner
+ authorization
+ f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific
+ g. All DSAP sessions MUST be invalidated when any of the following commands execute:
+
+ i. TPM_Delegate_CreateOwnerDelegation
+ (1) When Increment is TRUE
+ ii. TPM_Delegate_LoadOwnerDelegation
+ iii. TPM_Delegate_Manage
+
+ NOTE Done by the ordinal processing
+
+ entityType = TPM_ET_DEL_OWNER_BLOB
+ The entityValue parameter contains a delegation blob structure.
+ entityType = TPM_ET_DEL_ROW
+ The entityValue parameter contains a row number in the nv Delegation table which should be
+ used for the AuthData value.
+*/
+
+TPM_RESULT TPM_Process_DSAP(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_ENTITY_TYPE entityType; /* The type of delegation information to use */
+ TPM_KEY_HANDLE keyHandle = 0; /* Key for which delegated authority corresponds, or 0 if
+ delegated owner activity. Only relevant if entityValue
+ equals TPM_DELEGATE_USEKEY_BLOB */
+ TPM_NONCE nonceOddDSAP; /* The nonce generated by the caller associated with the
+ shared secret. */
+ TPM_SIZED_BUFFER entityValue; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or
+ index. MUST not be empty. If entityType is TPM_ET_DEL_ROW
+ then entityValue is a TPM_DELEGATE_INDEX */
+
+ /* 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_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */
+ unsigned char *stream; /* temp input stream */
+ uint32_t stream_size;
+ TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob;
+ TPM_DELEGATE_KEY_BLOB k1DelegateKeyBlob;
+ TPM_KEY *delKey; /* key corresponding to keyHandle */
+ TPM_BOOL parentPCRStatus;
+ TPM_DELEGATE_SENSITIVE s1DelegateSensitive;
+ uint32_t delegateRowIndex;
+ TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow;
+ TPM_SECRET *a1AuthValue = NULL;
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+
+ TPM_BOOL got_handle = FALSE;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization
+ state. */
+ TPM_NONCE nonceEvenDSAP; /* Nonce generated by TPM and associated with shared
+ secret. */
+
+ printf("TPM_Process_DSAP: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&entityValue); /* freed @1 */
+ TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @2 */
+ TPM_DelegateKeyBlob_Init(&k1DelegateKeyBlob); /* freed @3 */
+ TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* get entityType */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DSAP: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* get nonceOddDSAP */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DSAP: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_Nonce_Load(nonceOddDSAP, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command + sizeof(uint32_t); /* audit entityValue but not entityValueSize */
+ /* get entityValue */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&entityValue, &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_NOT_SHUTDOWN |
+ TPM_CHECK_OWNER |
+ TPM_CHECK_NO_LOCKOUT));
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DSAP: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ if (returnCode == TPM_SUCCESS) {
+ /* use a temporary copy so the original values are not moved */
+ stream = entityValue.buffer;
+ stream_size = entityValue.size;
+ switch (entityType & 0x00ff) { /* entity type LSB is the actual entity type */
+ case TPM_ET_DEL_OWNER_BLOB:
+ /* 1. If entityType == TPM_ET_DEL_OWNER_BLOB */
+ /* a. Map entityValue to B1 a TPM_DELEGATE_OWNER_BLOB */
+ /* b. Validate that B1 is a valid TPM_DELEGATE_OWNER_BLOB, return TPM_WRONG_ENTITYTYPE
+ on error */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateOwnerBlob_Load(&b1DelegateOwnerBlob,
+ &stream, &stream_size);
+ if (returnCode != TPM_SUCCESS) {
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* c. Locate B1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to
+ indicate row, return TPM_BADINDEX if not found */
+ /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */
+ /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ b1DelegateOwnerBlob.pub.familyID);
+ }
+ /* f. Verify that B1->verificationCount equals FR -> verificationCount. */
+ if (returnCode == TPM_SUCCESS) {
+ if (b1DelegateOwnerBlob.pub.verificationCount != familyRow->verificationCount) {
+ printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n",
+ b1DelegateOwnerBlob.pub.verificationCount, familyRow->verificationCount);
+ returnCode = TPM_FAMILYCOUNT;
+ }
+ }
+ /* g. Validate the integrity of the blob */
+ /* i. Copy B1 -> integrityDigest to H2 */
+ /* ii. Set B1 -> integrityDigest to NULL */
+ /* iii. Create H3 the HMAC of B1 using tpmProof as the secret */
+ /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &b1DelegateOwnerBlob, /* structure */
+ b1DelegateOwnerBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store,/* store function */
+ TPM_AUTHFAIL); /* error code */
+ }
+ /* h. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting B1 -> sensitiveArea using
+ TPM_DELEGATE_KEY */
+ /* i. Validate S1 values */
+ /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */
+ /* ii. Return TPM_BAD_DELEGATE on error */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateSensitive_DecryptEncData
+ (&s1DelegateSensitive, /* decrypted data */
+ &(b1DelegateOwnerBlob.sensitiveArea),
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ /* j. Set A1 to S1 -> authValue */
+ if (returnCode == TPM_SUCCESS) {
+ a1AuthValue = &(s1DelegateSensitive.authValue);
+ }
+ break;
+ case TPM_ET_DEL_ROW:
+ /* 2. Else if entityType == TPM_ET_DEL_ROW */
+ /* a. Verify that entityValue points to a valid row in the delegation table. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&delegateRowIndex, &stream, &stream_size);
+ }
+ /* b. Set D1 to the delegation information in the row. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_DelegateTable_GetValidRow(&d1DelegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ delegateRowIndex);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* c. Set A1 to D1->authValue. */
+ a1AuthValue = &d1DelegateTableRow->authValue;
+ /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate
+ that row, return TPM_BADINDEX if not found */
+ /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */
+ /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ returnCode =
+ TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ d1DelegateTableRow->pub.familyID);
+ }
+ /* g. Verify that D1->verificationCount equals FR -> verificationCount. */
+ if (returnCode == TPM_SUCCESS) {
+ if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) {
+ printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n",
+ d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount);
+ returnCode = TPM_FAMILYCOUNT;
+ }
+ }
+ break;
+ case TPM_ET_DEL_KEY_BLOB:
+ /* 3. Else if entityType == TPM_ET_DEL_KEY_BLOB */
+ /* a. Map entityValue to K1 a TPM_DELEGATE_KEY_BLOB */
+ /* b. Validate that K1 is a valid TPM_DELEGATE_KEY_BLOB, return TPM_WRONG_ENTITYTYPE on
+ error */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateKeyBlob_Load(&k1DelegateKeyBlob, &stream, &stream_size);
+ if (returnCode != TPM_SUCCESS) {
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* c. Locate K1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to
+ indicate that row, return TPM_BADINDEX if not found */
+ /* d. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */
+ /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ k1DelegateKeyBlob.pub.familyID);
+ }
+ /* f. Verify that K1 -> pub -> verificationCount equals FR -> verificationCount. */
+ if (returnCode == TPM_SUCCESS) {
+ if (k1DelegateKeyBlob.pub.verificationCount != familyRow->verificationCount) {
+ printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n",
+ k1DelegateKeyBlob.pub.verificationCount, familyRow->verificationCount);
+ returnCode = TPM_FAMILYCOUNT;
+ }
+ }
+ /* g. Validate the integrity of the blob */
+ /* i. Copy K1 -> integrityDigest to H2 */
+ /* ii. Set K1 -> integrityDigest to NULL */
+ /* iii. Create H3 the HMAC of K1 using tpmProof as the secret */
+ /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &k1DelegateKeyBlob, /* structure */
+ k1DelegateKeyBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ }
+ /* h. Validate that K1 -> pubKeyDigest identifies keyHandle, return TPM_KEYNOTFOUND on
+ error */
+ /* get the TPM_KEY corresponding to keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&delKey,
+ &parentPCRStatus,
+ tpm_state,
+ keyHandle,
+ TRUE, /* read only */
+ TRUE, /* ignore PCRs at setup */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1_CheckStructure(k1DelegateKeyBlob.pubKeyDigest,
+ &(delKey->pubKey),
+ (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store,
+ TPM_KEYNOTFOUND);
+ }
+ /* i. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting K1 -> sensitiveArea using
+ TPM_DELEGATE_KEY */
+ /* j. Validate S1 values */
+ /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */
+ /* ii. Return TPM_BAD_DELEGATE on error */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateSensitive_DecryptEncData
+ (&s1DelegateSensitive, /* decrypted data */
+ &(k1DelegateKeyBlob.sensitiveArea),
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ /* k. Set A1 to S1 -> authValue */
+ if (returnCode == TPM_SUCCESS) {
+ a1AuthValue = &(s1DelegateSensitive.authValue);
+ }
+ break;
+ default:
+ /* 4. Else return TPM_BAD_PARAMETER */
+ printf("TPM_Process_DSAP: Error, bad entityType %04hx\n", entityType);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 5. Generate a new authorization session handle and reserve space to save protocol
+ identification, shared secret, pcrInfo, both nonces, ADIP encryption scheme, delegated
+ permission bits and any other information the TPM needs to manage the session. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetNewHandle(&authSession,
+ &authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DSAP: Using authHandle %08x\n", authHandle);
+ got_handle = TRUE;
+ /* save protocol identification */
+ authSession->protocolID = TPM_PID_DSAP;
+ /* save the ADIP encryption scheme */
+ authSession->adipEncScheme = (entityType >> 8) & 0x00ff;
+ /* NOTE: added: Check if the ADIP encryption scheme specified by entityType is supported, if
+ not return TPM_INAPPROPRIATE_ENC. */
+ returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme,
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (entityType == TPM_ET_DEL_KEY_BLOB) {
+ /* map the entity type to a key */
+ authSession->entityTypeByte = TPM_ET_KEYHANDLE;
+ /* Save the entityDigest for comparison during use. */
+ TPM_Digest_Copy(authSession->entityDigest, delKey->tpm_store_asymkey->pubDataDigest);
+ /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session
+ use. */
+ returnCode =TPM_DelegatePublic_Copy(&(authSession->pub), &(k1DelegateKeyBlob.pub));
+ }
+ else {
+ /* owner or blob or delegate row are both owner auth */
+ authSession->entityTypeByte = TPM_ET_OWNER;
+ /* Save the entityDigest for comparison during use. */
+ TPM_Digest_Copy(authSession->entityDigest, tpm_state->tpm_permanent_data.ownerAuth);
+ /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session
+ use. */
+ if (entityType == TPM_ET_DEL_OWNER_BLOB) {
+ returnCode = TPM_DelegatePublic_Copy(&(authSession->pub),
+ &(b1DelegateOwnerBlob.pub));
+ }
+ else { /* TPM_ET_DEL_ROW */
+ returnCode = TPM_DelegatePublic_Copy(&(authSession->pub),
+ &(d1DelegateTableRow->pub));
+ }
+ }
+ /* 6. Read two new values from the RNG to generate nonceEven and nonceEvenOSAP. */
+ TPM_Nonce_Generate(authSession->nonceEven);
+ TPM_Nonce_Generate(nonceEvenDSAP);
+ }
+ /* 7. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC
+ calculation is A1. The input to the HMAC calculation is the concatenation of nonces
+ nonceEvenOSAP and nonceOddOSAP. The output of the HMAC calculation is the shared secret
+ which is saved in the authorization area associated with authHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_DSAP: authData", *a1AuthValue);
+ TPM_PrintFour("TPM_Process_DSAP: nonceEvenOSAP", nonceEvenDSAP);
+ TPM_PrintFour("TPM_Process_DSAP: nonceOddOSAP", nonceOddDSAP);
+ returnCode = TPM_HMAC_Generate(authSession->sharedSecret,
+ *a1AuthValue, /* HMAC key */
+ TPM_NONCE_SIZE, nonceEvenDSAP,
+ TPM_NONCE_SIZE, nonceOddDSAP,
+ 0, NULL);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DSAP: 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;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ /* append authHandle */
+ returnCode = TPM_Sbuffer_Append32(response, authHandle);
+ }
+ /* append nonceEven */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, authSession->nonceEven);
+ }
+ /* append nonceEvenDSAP */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, nonceEvenDSAP);
+ }
+ /* 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 */
+ }
+ /* 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 the handle is not being returned, it should be terminated */
+ if (((returnCode != 0) || (rcf != 0)) && got_handle) {
+ TPM_AuthSessionData_Delete(authSession);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&entityValue); /* @1 */
+ TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @2 */
+ TPM_DelegateKeyBlob_Delete(&k1DelegateKeyBlob); /* @3 */
+ TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */
+ return rcf;
+}
+
+/* TPM_DSAPDelegate() implements the actions common to TPM_DSAP and TPM_OSAP with
+ ownerReference pointing to a delegate row.
+
+ 'entityDigest' and 'authData' are returned, as they are used by common code.
+ authSession.
+
+ protocolID is changed to DSAP.
+ the TPM_DELEGATE_PUBLIC blob is copied to the OSAP/DSAP session structure.
+*/
+
+static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest,
+ TPM_SECRET **authData,
+ TPM_AUTH_SESSION_DATA *authSession,
+ tpm_state_t *tpm_state,
+ uint32_t delegateRowIndex)
+{
+ TPM_RESULT rc = 0;
+ TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow;
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+
+ printf("TPM_DSAPCommon: Index %u\n", delegateRowIndex);
+ /* 2. Else if entityType == TPM_ET_DEL_ROW */
+ /* a. Verify that entityValue points to a valid row in the delegation table. */
+ /* b. Set d1 to the delegation information in the row. */
+ if (rc == TPM_SUCCESS) {
+ rc = TPM_DelegateTable_GetValidRow(&d1DelegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ delegateRowIndex);
+ }
+ if (rc == TPM_SUCCESS) {
+ /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that
+ row, return TPM_BADINDEX if not found */
+ /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */
+ /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ rc = TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ d1DelegateTableRow->pub.familyID);
+ }
+ /* g. Verify that d1->verificationCount equals FR -> verificationCount. */
+ if (rc == TPM_SUCCESS) {
+ if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) {
+ printf("TPM_DSAPCommon: Error, verificationCount mismatch %u %u\n",
+ d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount);
+ rc = TPM_FAMILYCOUNT;
+ }
+ }
+ if (rc == TPM_SUCCESS) {
+ /* c. Set a1 to d1->authValue. */
+ *authData = &d1DelegateTableRow->authValue; /* use owner delegate authorization value */
+ /* indicate later that the entity is the 'owner'. Use the real owner auth because the
+ ordinal doesn't know about the delegation */
+ *entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth);
+ authSession->protocolID = TPM_PID_DSAP; /* change from OSAP to DSAP */
+ /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session
+ use. */
+ rc = TPM_DelegatePublic_Copy(&(authSession->pub),
+ &(d1DelegateTableRow->pub));
+ }
+ return rc;
+}
+
+/* 18.4 TPM_SetOwnerPointer rev 109
+
+ This command will set a reference to which secret the TPM will use when executing an owner secret
+ related OIAP or OSAP session.
+
+ This command should only be used to provide an owner delegation function for legacy code that
+ does not itself support delegation. Normally, TPM_STCLEAR_DATA->ownerReference points to
+ TPM_KH_OWNER, indicating that OIAP and OSAP sessions should use the owner authorization. This
+ command allows ownerReference to point to an index in the delegation table, indicating that
+ OIAP and OSAP sessions should use the delegation authorization.
+
+ In use, a TSS supporting delegation would create and load the owner delegation and set the owner
+ pointer to that delegation. From then on, a legacy TSS application would use its OIAP and OSAP
+ sessions with the delegated owner authorization.
+
+ Since this command is not authorized, the ownerReference is open to DoS attacks. Applications can
+ attempt to recover from a failing owner authorization by resetting ownerReference to an
+ appropriate value.
+
+ This command intentionally does not clear OSAP sessions. A TPM 1.1 application gets the benefit
+ of owner delegation, while the original owner can use a pre-existing OSAP session with the actual
+ owner authorization.
+*/
+
+TPM_RESULT TPM_Process_SetOwnerPointer(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_ENTITY_TYPE entityType; /* The type of entity in use */
+ uint32_t entityValue = 0; /* The selection value based on entityType */
+
+ /* 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_STCLEAR_DATA *v1StClearData;
+ TPM_DELEGATE_TABLE_ROW *b1DelegateTableRow; /* delegate row indicated by entityValue */
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_SetOwnerPointer: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get entityType */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get entityValue */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SetOwnerPointer: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&entityValue, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SetOwnerPointer: entityValue %08x\n", entityValue);
+ }
+ /* 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_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_SetOwnerPointer: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Map TPM_STCLEAR_DATA to V1 */
+ if (returnCode == TPM_SUCCESS) {
+ v1StClearData = &(tpm_state->tpm_stclear_data);
+ /* 2. If entityType = TPM_ET_DEL_ROW */
+ if (entityType == TPM_ET_DEL_ROW) {
+ /* a. This value indicates that the entity is a delegate row. entityValue is a delegate
+ index in the delegation table. */
+ /* b. Validate that entityValue points to a legal row within the delegate table stored
+ within the TPM. If not return TPM_BADINDEX */
+ /* i. Set D1 to the delegation information in the row. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_DelegateTable_GetValidRow(&b1DelegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ entityValue);
+
+ }
+ /* c. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that
+ row, return TPM_BADINDEX if not found. */
+ /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */
+ /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ b1DelegateTableRow->pub.familyID);
+ }
+ /* f. Verify that B1->verificationCount equals FR -> verificationCount. */
+ if (returnCode == TPM_SUCCESS) {
+ if (b1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) {
+ printf("TPM_Process_SetOwnerPointer: Error, "
+ "verificationCount mismatch %u %u\n",
+ b1DelegateTableRow->pub.verificationCount, familyRow->verificationCount);
+ returnCode = TPM_FAMILYCOUNT;
+ }
+ }
+ /* g. The TPM sets V1-> ownerReference to entityValue */
+ /* h. Return TPM_SUCCESS */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n",
+ entityValue);
+ v1StClearData->ownerReference = entityValue;
+ }
+ }
+ /* 3. else if entityType = TPM_ET_OWNER */
+ else if (entityType == TPM_ET_OWNER) {
+ /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */
+ /* b. The TPM sets V1-> ownerReference to TPM_KH_OWNER */
+ /* c. Return TPM_SUCCESS */
+ printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n", TPM_KH_OWNER);
+ v1StClearData->ownerReference = TPM_KH_OWNER;
+ }
+ /* 4. Return TPM_BAD_PARAMETER */
+ else {
+ printf("TPM_Process_SetOwnerPointer: Error, bad entityType\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_SetOwnerPointer: 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;
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 27.1.2 TPM_Terminate_Handle rev 87
+
+ This allows the TPM manager to clear out information in a session handle.
+
+ The TPM may maintain the authorization session even though a key attached to it has been unloaded
+ or the authorization session itself has been unloaded in some way. When a command is executed
+ that requires this session, it is the responsibility of the external software to load both the
+ entity and the authorization session information prior to command execution.
+
+ The TPM SHALL terminate the session and destroy all data associated with the session indicated.
+*/
+
+TPM_RESULT TPM_Process_TerminateHandle(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_AUTHHANDLE authHandle;
+
+ /* 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 */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_TerminateHandle: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* get handle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&authHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* 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_NOT_SHUTDOWN |
+ TPM_CHECK_NO_LOCKOUT));
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_TerminateHandle: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* terminate the handle */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_TerminateHandle: Using authHandle %08x\n", authHandle);
+ returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions,
+ authHandle);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_TerminateHandle: 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;
+ /* 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 */
+ }
+ /* 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);
+ }
+ return rcf;
+}
+
+/* 22.1 TPM_FlushSpecific rev 104
+
+ TPM_FlushSpecific flushes from the TPM a specific handle.
+
+ TPM_FlushSpecific releases the resources associated with the given handle.
+*/
+
+TPM_RESULT TPM_Process_FlushSpecific(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_HANDLE handle; /* The handle of the item to flush */
+ TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being flushed */
+
+ /* 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 */
+ uint32_t r1Resource; /* the context resource being flushed */
+ TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_FlushSpecific: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* get handle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&handle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get resourceType parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_FlushSpecific: Handle %08x\n", handle);
+ returnCode = TPM_Load32(&resourceType, &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_NOT_SHUTDOWN |
+ TPM_CHECK_NO_LOCKOUT));
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_FlushSpecific: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ if (returnCode == TPM_SUCCESS) {
+ switch (resourceType) {
+ case TPM_RT_CONTEXT:
+ /* 1. If resourceType is TPM_RT_CONTEXT */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_FlushSpecific: Flushing context count %08x\n", handle);
+ /* a. The handle for a context is not a handle but the "context count" value. The
+ TPM uses the "context count" value to locate the proper contextList entry and
+ sets R1 to the contextList entry */
+ returnCode = TPM_ContextList_GetEntry(&r1Resource, /* index into
+ contextList[] */
+ tpm_state->tpm_stclear_data.contextList,
+ handle);
+ /* 7. Validate that R1 determined by resourceType and handle points to a valid
+ allocated resource. Return TPM_BAD_PARAMETER on error. */
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_FlushSpecific: Error, context count %08x not found\n",
+ handle);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 8. Invalidate R1 and all internal resources allocated to R1 */
+ /* a. Resources include authorization sessions */
+ if (returnCode == TPM_SUCCESS) {
+ /* setting the entry to 0 prevents the session from being reloaded. */
+ tpm_state->tpm_stclear_data.contextList[r1Resource] = 0;
+ }
+ break;
+ case TPM_RT_KEY:
+ /* 2. Else if resourceType is TPM_RT_KEY */
+ /* a. Set R1 to the key pointed to by handle */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_FlushSpecific: Flushing key handle %08x\n", handle);
+ returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ handle);
+ /* 7. Validate that R1 determined by resourceType and handle points to a valid
+ allocated resource. Return TPM_BAD_PARAMETER on error. */
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_FlushSpecific: Error, key handle %08x not found\n",
+ handle);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* b. If R1 -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */
+ if (returnCode == TPM_SUCCESS) {
+ if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) {
+ printf("TPM_Process_FlushSpecific: Error, keyHandle specifies owner evict\n");
+ returnCode = TPM_KEY_OWNER_CONTROL;
+ }
+ }
+ /* 8. Invalidate R1 and all internal resources allocated to R1 */
+ /* a. Resources include authorization sessions */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry);
+ }
+ break;
+ case TPM_RT_AUTH:
+ /* NOTE replaces deprecated TPM_Terminate_Handle */
+ /* 3. Else if resourceType is TPM_RT_AUTH */
+ /* a. Set R1 to the authorization session pointed to by handle */
+ /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated
+ resource. Return TPM_BAD_PARAMETER on error. */
+ /* 8. Invalidate R1 and all internal resources allocated to R1 */
+ /* a. Resources include authorization sessions */
+ printf("TPM_Process_FlushSpecific: Flushing authorization session handle %08x\n",
+ handle);
+ returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions,
+ handle);
+ break;
+ case TPM_RT_TRANS:
+ /* 4. Else if resourceType is TPM_RT_TRANS */
+ /* a. Set R1 to the transport session pointed to by handle */
+ /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated
+ resource. Return TPM_BAD_PARAMETER on error. */
+ /* 8. Invalidate R1 and all internal resources allocated to R1 */
+ /* a. Resources include authorization sessions */
+ printf("TPM_Process_FlushSpecific: Flushing transport session handle %08x\n", handle);
+ returnCode = TPM_TransportSessions_TerminateHandle
+ (tpm_state->tpm_stclear_data.transSessions,
+ handle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ break;
+ case TPM_RT_DAA_TPM:
+ /* 5. Else if resourceType is TPM_RT_DAA_TPM */
+ /* a. Set R1 to the DAA session pointed to by handle */
+ /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated
+ resource. Return TPM_BAD_PARAMETER on error. */
+ /* 8. Invalidate R1 and all internal resources allocated to R1 */
+ /* a. Resources include authorization sessions */
+ printf("TPM_Process_FlushSpecific: Flushing DAA session handle %08x\n", handle);
+ returnCode = TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions,
+ handle);
+ break;
+ default:
+ /* 6. Else return TPM_INVALID_RESOURCE */
+ printf("TPM_Process_FlushSpecific: Error, invalid resourceType %08x\n", resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_FlushSpecific: 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;
+ /* 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 */
+ }
+ /* 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);
+ }
+ return rcf;
+}
+
+/* 21.2 TPM_SaveContext rev 107
+
+ SaveContext saves a loaded resource outside the TPM. After successful execution of the command the
+ TPM automatically releases the internal memory for sessions but leaves keys in place.
+
+ The caller of the function uses the label field to add additional sequencing, anti-replay or other
+ items to the blob. The information does not need to be confidential but needs to be part of the
+ blob integrity.
+*/
+
+TPM_RESULT TPM_Process_SaveContext(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_HANDLE handle; /* Handle of the resource being saved. */
+ TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being saved */
+ BYTE label[TPM_CONTEXT_LABEL_SIZE]; /* Label for identification purposes */
+
+ /* 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_STORE_BUFFER b1_sbuffer; /* serialization of b1 */
+ TPM_STCLEAR_DATA *v1StClearData = NULL;
+ TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data = NULL; /* session table entry for the handle */
+ TPM_TRANSPORT_INTERNAL *tpm_transport_internal; /* transport table entry for the handle */
+ TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* daa session table entry for the handle */
+ TPM_NONCE *n1ContextNonce = NULL;
+ TPM_SYMMETRIC_KEY_TOKEN k1ContextKey = NULL;
+ TPM_STORE_BUFFER r1ContextSensitive; /* serialization of sensitive data clear text */
+ TPM_CONTEXT_SENSITIVE c1ContextSensitive;
+ TPM_CONTEXT_BLOB b1ContextBlob;
+ TPM_STORE_BUFFER c1_sbuffer; /* serialization of c1ContextSensitive */
+ uint32_t contextIndex = 0; /* free index in context list */
+ uint32_t space; /* free space in context list */
+ TPM_BOOL isZero;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_SaveContext: Ordinal Entry\n");
+ TPM_Sbuffer_Init(&b1_sbuffer); /* freed @1 */
+ TPM_Sbuffer_Init(&r1ContextSensitive); /* freed @2 */
+ TPM_ContextBlob_Init(&b1ContextBlob); /* freed @3 */
+ TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @4 */
+ TPM_Sbuffer_Init(&c1_sbuffer); /* freed @6 */
+ /*
+ get inputs
+ */
+ /* get handle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&handle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get resourceType */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: handle %08x\n", handle);
+ returnCode = TPM_Load32(&resourceType, &command, &paramSize);
+ }
+ /* get label */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: resourceType %08x\n", resourceType);
+ returnCode = TPM_Loadn(label, TPM_CONTEXT_LABEL_SIZE, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_SaveContext: label", label);
+ }
+ /* 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_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_SaveContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ v1StClearData = &(tpm_state->tpm_stclear_data);
+ }
+ /* 2. Validate that handle points to resource that matches resourceType, return
+ TPM_INVALID_RESOURCE on error */
+ /* 3. Validate that resourceType is a resource from the following list if not return
+ TPM_INVALID_RESOURCE */
+ if (returnCode == TPM_SUCCESS) {
+ switch (resourceType) {
+ case TPM_RT_KEY:
+ /* a. TPM_RT_KEY */
+ printf("TPM_Process_SaveContext: Resource is key handle %08x\n", handle);
+ /* check if the key handle is valid */
+ returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ handle);
+ break;
+ case TPM_RT_AUTH:
+ /* b. TPM_RT_AUTH */
+ printf("TPM_Process_SaveContext: Resource is session handle %08x\n", handle);
+ returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data,
+ v1StClearData->authSessions,
+ handle);
+ break;
+ case TPM_RT_TRANS:
+ /* c. TPM_RT_TRANS */
+ printf("TPM_Process_SaveContext: Resource is transport handle %08x\n", handle);
+ returnCode = TPM_TransportSessions_GetEntry(&tpm_transport_internal,
+ v1StClearData->transSessions,
+ handle);
+ break;
+ case TPM_RT_DAA_TPM:
+ /* d. TPM_RT_DAA_TPM */
+ printf("TPM_Process_SaveContext: Resource is DAA handle %08x\n", handle);
+ returnCode = TPM_DaaSessions_GetEntry(&tpm_daa_session_data,
+ v1StClearData->daaSessions,
+ handle);
+ break;
+ default:
+ printf("TPM_Process_SaveContext: Error, invalid resourceType %08x\n", resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ if (returnCode != 0) {
+ printf("TPM_Process_SaveContext: Error, handle %08x not found\n", handle);
+ returnCode = TPM_INVALID_RESOURCE;
+ }
+ }
+ /* 4. Locate the correct nonce */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: Locating nonce\n");
+ /* a. If resourceType is TPM_RT_KEY */
+ if (resourceType == TPM_RT_KEY) {
+ if (returnCode == TPM_SUCCESS) {
+ /* i. If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */
+ TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey);
+ if (isZero) {
+ /* (1) Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM
+ RNG */
+ returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey);
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* ii. Map N1 to TPM_STCLEAR_DATA -> contextNonceKey */
+ n1ContextNonce = &(tpm_state->tpm_stclear_data.contextNonceKey);
+ /* iii. If the key has TPM_KEY_CONTROL_OWNER_EVICT set then return TPM_OWNER_CONTROL
+ */
+ if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) {
+ printf("TPM_Process_SaveContext: Error, key under owner control\n");
+ returnCode = TPM_OWNER_CONTROL;
+ }
+ }
+ }
+ /* b. Else (resource not TPM_RT_KEY) */
+ else {
+ if (returnCode == TPM_SUCCESS) {
+ /* i. If V1 -> contextNonceSession is NULLS */
+ TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession);
+ if (isZero) {
+ /* (1) Set V1 -> contextNonceSession to the next value from the TPM RNG */
+ returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession);
+ }
+ }
+ /* ii. Map N1 to V1 -> contextNonceSession */
+ if (returnCode == TPM_SUCCESS) {
+ n1ContextNonce = &(v1StClearData->contextNonceSession);
+ }
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: Building sensitive data\n");
+ /* 5. Set K1 to TPM_PERMANENT_DATA -> contextKey */
+ k1ContextKey = tpm_state->tpm_permanent_data.contextKey;
+ /* 6. Create R1 by putting the sensitive part of the resource pointed to by handle into a
+ structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL
+ sensitive information of the resource is included in R1. */
+ /* NOTE Since the contextKey is a symmetric key, the entire resource is put into the
+ sensitiveData */
+ switch (resourceType) {
+ case TPM_RT_KEY:
+ returnCode = TPM_KeyHandleEntry_Store(&r1ContextSensitive, tpm_key_handle_entry);
+ break;
+ case TPM_RT_AUTH:
+ returnCode = TPM_AuthSessionData_Store(&r1ContextSensitive, tpm_auth_session_data);
+ break;
+ case TPM_RT_TRANS:
+ returnCode = TPM_TransportInternal_Store(&r1ContextSensitive, tpm_transport_internal);
+ break;
+ case TPM_RT_DAA_TPM:
+ returnCode = TPM_DaaSessionData_Store(&r1ContextSensitive, tpm_daa_session_data);
+ break;
+ default:
+ printf("TPM_Process_SaveContext: Error, invalid resourceType %08x", resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ }
+ /* 7. Create C1 a TPM_CONTEXT_SENSITIVE structure */
+ /* NOTE Done at TPM_ContextSensitive_Init() */
+ /* a. C1 forms the inner encrypted wrapper for the blob. All saved context blobs MUST include a
+ TPM_CONTEXT_SENSITIVE structure and the TPM_CONTEXT_SENSITIVE structure MUST be encrypted. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: Building TPM_CONTEXT_SENSITIVE\n");
+ /* b. Set C1 -> contextNonce to N1 */
+ TPM_Nonce_Copy(c1ContextSensitive.contextNonce, *n1ContextNonce);
+ /* c. Set C1 -> internalData to R1 */
+ returnCode = TPM_SizedBuffer_SetFromStore(&(c1ContextSensitive.internalData),
+ &r1ContextSensitive);
+ }
+ /* 8. Create B1 a TPM_CONTEXT_BLOB */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: Building TPM_CONTEXT_BLOB\n");
+ /* a. Set B1 -> tag to TPM_TAG_CONTEXTBLOB */
+ /* NOTE Done at TPM_ContextBlob_Init() */
+ /* b. Set B1 -> resourceType to resourceType */
+ b1ContextBlob.resourceType = resourceType;
+ /* c. Set B1 -> handle to handle */
+ b1ContextBlob.handle = handle;
+ /* d. Set B1 -> integrityDigest to NULL */
+ /* NOTE Done at TPM_ContextBlob_Init() */
+ /* e. Set B1 -> label to label */
+ memcpy(b1ContextBlob.label, label, TPM_CONTEXT_LABEL_SIZE);
+
+ }
+ /* f. Set B1 -> additionalData to information determined by the TPM manufacturer. This data will
+ help the TPM to reload and reset context. This area MUST NOT hold any data that is sensitive
+ (symmetric IV are fine, prime factors of an RSA key are not). */
+ /* i. For OSAP sessions, and for DSAP sessions attached to keys, the hash of the entity MUST be
+ included in additionalData */
+ /* NOTE Included in TPM_AUTH_SESSION_DATA. This is implementation defined, and the manufacturer
+ can put everything in sensitive data. */
+ /* g. Set B1 -> additionalSize to the size of additionalData */
+ /* NOTE Initialized by TPM_ContextBlob_Init() */
+ /* h. Set B1 -> sensitiveSize to the size of C1 */
+ /* i. Set B1 -> sensitiveData to C1 */
+ /* serialize C1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextSensitive_Store(&c1_sbuffer, &c1ContextSensitive);
+ }
+ /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_SetFromStore(&(b1ContextBlob.sensitiveData), &c1_sbuffer);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 9. If resourceType is TPM_RT_KEY */
+ if (resourceType == TPM_RT_KEY) {
+ /* a. Set B1 -> contextCount to 0 */
+ b1ContextBlob.contextCount = 0;
+ }
+ /* 10. Else */
+ else {
+ printf("TPM_Process_SaveContext: Processing session context count\n");
+ if (returnCode == TPM_SUCCESS) {
+ /* a. If V1 -> contextCount > 2^32-2 then */
+ if (v1StClearData->contextCount > 0xfffffffe) {
+ /* i. Return with TPM_TOOMANYCONTEXTS */
+ printf("TPM_Process_SaveContext: Error, too many contexts\n");
+ returnCode = TPM_TOOMANYCONTEXTS;
+ }
+ }
+ /* b. Else */
+ if (returnCode == TPM_SUCCESS) {
+ /* i. Validate that the TPM can still manage the new count value */
+ /* (1) If the distance between the oldest saved context and the contextCount is
+ too large return TPM_CONTEXT_GAP */
+ /* Since contextCount is uint32_t, this is not applicable here. From email: Does
+ the TPM have the ability to keep track of the context delta. It is possible to
+ keep track of things with just a byte or so internally, if this is done a gap of
+ greater than 2^16 or so might be too large, hence the context gap message */
+ }
+ /* ii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not
+ found exit with TPM_NOCONTEXTSPACE */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList);
+ if (space == 0) {
+ printf("TPM_Process_SaveContext: Error, no space in context list\n");
+ returnCode = TPM_NOCONTEXTSPACE;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* iii. Increment V1 -> contextCount by 1 */
+ v1StClearData->contextCount++;
+ /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */
+ v1StClearData->contextList[contextIndex] = v1StClearData->contextCount;
+ /* v. Set B1 -> contextCount to V1 -> contextCount */
+ b1ContextBlob.contextCount = v1StClearData->contextCount;
+ }
+ /* c. The TPM MUST invalidate all information regarding the resource except for
+ information needed for reloading */
+ if (returnCode == TPM_SUCCESS) {
+ switch (resourceType) {
+ case TPM_RT_AUTH:
+ returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions,
+ handle);
+ break;
+ case TPM_RT_TRANS:
+ returnCode = TPM_TransportSessions_TerminateHandle
+ (v1StClearData->transSessions,
+ handle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ break;
+ case TPM_RT_DAA_TPM:
+ returnCode = TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions,
+ handle);
+ break;
+ default:
+ printf("TPM_Process_SaveContext: Error, invalid resourceType %08x",
+ resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ }
+ }
+ }
+ /* 11. Calculate B1 -> integrityDigest the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as
+ the secret. NOTE It is calculated on the cleartext data */
+ if (returnCode == TPM_SUCCESS) {
+ /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the
+ HMAC is generated. The result is put back into the structure. */
+ printf("TPM_Process_SaveContext: Digesting TPM_CONTEXT_BLOB\n");
+ returnCode = TPM_HMAC_GenerateStructure
+ (b1ContextBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &b1ContextBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */
+ }
+ /* 12. Create E1 by encrypting C1 using K1 as the key */
+ /* a. Set B1 -> sensitiveSize to the size of E1 */
+ /* b. Set B1 -> sensitiveData to E1 */
+ if (returnCode == TPM_SUCCESS) {
+ /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now,
+ before the encrypted data is stored there. */
+ TPM_SizedBuffer_Delete(&(b1ContextBlob.sensitiveData));
+ returnCode = TPM_SymmetricKeyData_EncryptSbuffer(&(b1ContextBlob.sensitiveData),
+ &c1_sbuffer,
+ k1ContextKey);
+ }
+ /* 13. Set contextSize to the size of B1 */
+ /* 14. Return B1 in contextBlob */
+ /* Since the redundant size parameter must be returned, the TPM_CONTEXT_BLOB is serialized
+ first. Later, rather than the usual _Store to the response, the already serialized buffer is
+ stored. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Store(&b1_sbuffer, &b1ContextBlob);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_SaveContext: 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 contextSize and contextBlob */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &b1_sbuffer);
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_Sbuffer_Delete(&b1_sbuffer); /* @1 */
+ TPM_Sbuffer_Delete(&r1ContextSensitive); /* @2 */
+ TPM_ContextBlob_Delete(&b1ContextBlob); /* @3 */
+ TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @4 */
+ TPM_Sbuffer_Delete(&c1_sbuffer); /* @6 */
+ return rcf;
+}
+
+/* 21.3 TPM_LoadContext rev 107
+
+ TPM_LoadContext loads into the TPM a previously saved context. The command returns the handle.
+*/
+
+TPM_RESULT TPM_Process_LoadContext(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_HANDLE entityHandle; /* The handle the TPM MUST use to locate the entity ties
+ to the OSAP/DSAP session */
+ TPM_BOOL keepHandle; /* Indication if the handle MUST be preserved */
+ uint32_t contextSize; /* The size of the following context blob */
+ TPM_CONTEXT_BLOB b1ContextBlob; /* The context blob */
+
+ /* 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 key_added = FALSE; /* key has been added to handle list */
+ TPM_BOOL auth_session_added = FALSE;
+ TPM_BOOL trans_session_added = FALSE;
+ TPM_BOOL daa_session_added = FALSE;
+ TPM_STCLEAR_DATA *v1StClearData = NULL;
+ unsigned char *m1Decrypt; /* decrypted sensitive data */
+ uint32_t m1_length; /* actual data in m1 */
+ unsigned char *stream;
+ uint32_t stream_size;
+ TPM_CONTEXT_SENSITIVE c1ContextSensitive;
+ TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry;
+ TPM_AUTH_SESSION_DATA tpm_auth_session_data; /* loaded authorization session */
+ TPM_TRANSPORT_INTERNAL tpm_transport_internal; /* loaded transport session */
+ TPM_DAA_SESSION_DATA tpm_daa_session_data; /* loaded daa session */
+ TPM_DIGEST entityDigest; /* digest of the entity corresponding to
+ entityHandle */
+ uint32_t contextIndex;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_LoadContext: Ordinal Entry\n");
+ TPM_ContextBlob_Init(&b1ContextBlob); /* freed @1 */
+ TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */
+ m1Decrypt = NULL; /* freed @2 */
+ TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @3 */
+ TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */
+ TPM_TransportInternal_Init(&tpm_transport_internal); /* freed @5 */
+ TPM_DaaSessionData_Init(&tpm_daa_session_data); /* freed @6 */
+ /*
+ get inputs
+ */
+ /* get parameter entityHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&entityHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get keepHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: entityHandle %08x\n", entityHandle);
+ returnCode = TPM_LoadBool(&keepHandle, &command, &paramSize);
+ }
+ /* get contextSize parameter (redundant, not used) */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: keepHandle %02x\n", keepHandle);
+ returnCode = TPM_Load32(&contextSize, &command, &paramSize);
+ }
+ /* get contextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&b1ContextBlob, &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_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_LoadContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Map contextBlob to B1, a TPM_CONTEXT_BLOB structure */
+ /* NOTE Done by TPM_ContextBlob_Load() */
+ if (returnCode == TPM_SUCCESS) {
+ /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */
+ v1StClearData = &(tpm_state->tpm_stclear_data);
+ /* 3. Create M1 by decrypting B1 -> sensitiveData using TPM_PERMANENT_DATA -> contextKey */
+ printf("TPM_Process_LoadContext: Decrypting sensitiveData\n");
+ returnCode = TPM_SymmetricKeyData_Decrypt(&m1Decrypt, /* decrypted data */
+ &m1_length, /* length decrypted data */
+ b1ContextBlob.sensitiveData.buffer, /* encrypt */
+ b1ContextBlob.sensitiveData.size,
+ tpm_state->tpm_permanent_data.contextKey);
+ }
+ /* 4. Create C1 and R1 by splitting M1 into a TPM_CONTEXT_SENSITIVE structure and internal
+ resource data */
+ /* NOTE R1 is manufacturer specific data that might be part of the blob. This implementation
+ does not use R1 */
+ if (returnCode == TPM_SUCCESS) {
+ stream = m1Decrypt;
+ stream_size = m1_length;
+ returnCode = TPM_ContextSensitive_Load(&c1ContextSensitive, &stream, &stream_size);
+ }
+ /* Parse the TPM_CONTEXT_SENSITIVE -> internalData depending on the resource type */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Parsing TPM_CONTEXT_SENSITIVE -> internalData\n");
+ stream = c1ContextSensitive.internalData.buffer;
+ stream_size = c1ContextSensitive.internalData.size;
+ switch (b1ContextBlob.resourceType) {
+ case TPM_RT_KEY:
+ printf("TPM_Process_LoadContext: Loading TPM_KEY_HANDLE_ENTRY\n");
+ returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size);
+ break;
+ case TPM_RT_AUTH:
+ printf("TPM_Process_LoadContext: Loading TPM_AUTH_SESSION_DATA\n");
+ returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size);
+ printf("TPM_Process_LoadContext: protocolID %02x entityTypeByte %02x\n",
+ tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte);
+ break;
+ case TPM_RT_TRANS:
+ printf("TPM_Process_LoadContext: Loading TPM_TRANSPORT_INTERNAL\n");
+ returnCode = TPM_TransportInternal_Load(&tpm_transport_internal,
+ &stream, &stream_size);
+ break;
+ case TPM_RT_DAA_TPM:
+ printf("TPM_Process_LoadContext: Loading TPM_DAA_SESSION_DATA\n");
+ returnCode = TPM_DaaSessionData_Load(&tpm_daa_session_data, &stream, &stream_size);
+ printf("TPM_Process_LoadContext: stage %u\n",
+ tpm_daa_session_data.DAA_session.DAA_stage);
+ break;
+ default:
+ printf("TPM_Process_LoadContext: Error, invalid resourceType %08x",
+ b1ContextBlob.resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ }
+ /* 5. Check contextNonce */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Checking contextNonce\n");
+ /* a. If B1 -> resourceType is NOT TPM_RT_KEY */
+ if (b1ContextBlob.resourceType != TPM_RT_KEY) {
+ /* i. If C1 -> contextNonce does not equal V1 -> contextNonceSession return
+ TPM_BADCONTEXT */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession,
+ c1ContextSensitive.contextNonce);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Error comparing non-key contextNonce\n");
+ returnCode = TPM_BADCONTEXT;
+ }
+ }
+ /* ii. Validate that the resource pointed to by the context is loaded (i.e. for OSAP the
+ key referenced is loaded and DSAP connected to the key) return TPM_RESOURCEMISSING */
+ /* (1) For OSAP sessions and for DSAP sessions attached to keys, the TPM MUST validate
+ that the hash of the entity matches the entity held by the TPM */
+ /* (2) For OSAP and DSAP sessions referring to a key, verify that entityHandle
+ identifies the key linked to this OSAP/DSAP session, if not return TPM_BAD_HANDLE. */
+ if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType == TPM_RT_AUTH)) {
+ if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) ||
+ (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) {
+ /* check that the entity is loaded, and get the entity's digest */
+ switch (tpm_auth_session_data.entityTypeByte) {
+ case TPM_ET_KEYHANDLE:
+ returnCode = TPM_LoadContext_CheckKeyLoaded(tpm_state,
+ entityHandle,
+ entityDigest);
+ break;
+ case TPM_ET_OWNER:
+ returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state,
+ entityDigest);
+ break;
+ case TPM_ET_SRK:
+ returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state,
+ entityDigest);
+ break;
+ case TPM_ET_COUNTER:
+ returnCode = TPM_LoadContext_CheckCounterLoaded(tpm_state,
+ entityHandle,
+ entityDigest);
+ break;
+ case TPM_ET_NV:
+ returnCode = TPM_LoadContext_CheckNvLoaded(tpm_state,
+ entityHandle,
+ entityDigest);
+ break;
+ default:
+ printf("TPM_Process_LoadContext: Error, invalid session entityType %02x\n",
+ tpm_auth_session_data.entityTypeByte);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ break;
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode= TPM_Digest_Compare(entityDigest,
+ tpm_auth_session_data.entityDigest);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Error, "
+ "OSAP or DSAP entityDigest mismatch\n");
+ returnCode = TPM_RESOURCEMISSING;
+ }
+ }
+ }
+ }
+ }
+ /* b. Else (TPM_RT_KEY) */
+ else {
+ /* i. If C1 -> internalData -> parentPCRStatus is FALSE and C1 -> internalData ->
+ isVolatile is FALSE */
+ /* NOTE parentPCRStatus and keyFlags are not security sensitive data, could be in
+ additionalData */
+ /* (1) Ignore C1 -> contextNonce */
+ if (returnCode == TPM_SUCCESS) {
+ if (tpm_key_handle_entry.parentPCRStatus ||
+ (tpm_key_handle_entry.key->keyFlags & TPM_ISVOLATILE)) {
+ /* ii. else */
+ /* (1) If C1 -> contextNonce does not equal TPM_STCLEAR_DATA -> contextNonceKey
+ return TPM_BADCONTEXT */
+ returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceKey,
+ c1ContextSensitive.contextNonce);
+ if (returnCode != 0) {
+ printf("TPM_Process_LoadContext: Error comparing contextNonceKey\n");
+ returnCode = TPM_BADCONTEXT;
+ }
+ }
+ }
+ }
+ }
+ /* 6. Validate the structure */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Checking integrityDigest\n");
+ /* a. Set H1 to B1 -> integrityDigest */
+ /* NOTE Done by TPM_HMAC_CheckStructure() */
+ /* b. Set B1 -> integrityDigest to all zeros */
+ /* NOTE Done by TPM_HMAC_CheckStructure() */
+ /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */
+ returnCode = TPM_SizedBuffer_Set(&(b1ContextBlob.sensitiveData), m1_length, m1Decrypt);
+ }
+ /* d. Create H2 the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as the HMAC key */
+ /* e. If H2 does not equal H1 return TPM_BADCONTEXT */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &b1ContextBlob, /* structure */
+ b1ContextBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */
+ TPM_BADCONTEXT); /* error code */
+ }
+ /* 9. If B1 -> resourceType is NOT TPM_RT_KEY */
+ if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType != TPM_RT_KEY)) {
+ printf("TPM_Process_LoadContext: Checking contextCount\n");
+ /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 ->
+ TPM_CONTEXT_BLOB -> contextCount */
+ /* b. If not found then return TPM_BADCONTEXT */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextList_GetEntry(&contextIndex,
+ v1StClearData->contextList,
+ b1ContextBlob.contextCount);
+ }
+ /* c. Set V1 -> contextList[contextIndex] to 0 */
+ if (returnCode == TPM_SUCCESS) {
+ v1StClearData->contextList[contextIndex] = 0;
+ }
+ }
+ /* 10. Process B1 to return the resource back into TPM use */
+ /* restore the entity, try to keep the handle as 'handle' */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: Adding entry to table\n");
+ switch (b1ContextBlob.resourceType) {
+ case TPM_RT_KEY:
+ returnCode = TPM_KeyHandleEntries_AddEntry(&(b1ContextBlob.handle),
+ keepHandle,
+ tpm_state->tpm_key_handle_entries,
+ &tpm_key_handle_entry);
+ key_added = TRUE;
+ break;
+ case TPM_RT_AUTH:
+ returnCode = TPM_AuthSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */
+ keepHandle,
+ v1StClearData->authSessions,
+ &tpm_auth_session_data);
+ auth_session_added = TRUE;
+ break;
+ case TPM_RT_TRANS:
+ returnCode = TPM_TransportSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */
+ keepHandle,
+ v1StClearData->transSessions,
+ &tpm_transport_internal);
+ trans_session_added = TRUE;
+ break;
+ case TPM_RT_DAA_TPM:
+ returnCode = TPM_DaaSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */
+ keepHandle,
+ v1StClearData->daaSessions,
+ &tpm_daa_session_data);
+ daa_session_added = TRUE;
+ break;
+ default:
+ printf("TPM_Process_LoadContext: Error, invalid resourceType %08x\n",
+ b1ContextBlob.resourceType);
+ returnCode = TPM_INVALID_RESOURCE;
+ break;
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_LoadContext: 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) {
+ /* return handle */
+ returnCode = TPM_Sbuffer_Append32(response, b1ContextBlob.handle);
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ /* if there was a failure, roll back */
+ if ((rcf != 0) || (returnCode != TPM_SUCCESS)) {
+ TPM_Key_Delete(tpm_key_handle_entry.key); /* free on error */
+ free(tpm_key_handle_entry.key); /* free on error */
+ if (key_added) {
+ /* if there was a failure and inKey was stored in the handle list, free the handle.
+ Ignore errors, since only one error code can be returned. */
+ TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries,
+ b1ContextBlob.handle);
+ }
+ if (auth_session_added) {
+ TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, b1ContextBlob.handle);
+ }
+ if (trans_session_added) {
+ TPM_TransportSessions_TerminateHandle(v1StClearData->transSessions,
+ b1ContextBlob.handle,
+ &(tpm_state->tpm_stany_flags.transportExclusive));
+ }
+ if (daa_session_added) {
+ TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions, b1ContextBlob.handle);
+ }
+ }
+ TPM_ContextBlob_Delete(&b1ContextBlob); /* @1 */
+ free(m1Decrypt); /* @2 */
+ TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @3 */
+ TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */
+ TPM_TransportInternal_Delete(&tpm_transport_internal); /* @5 */
+ TPM_DaaSessionData_Delete(&tpm_daa_session_data); /* @6 */
+ return rcf;
+}
+
+/* TPM_LoadContext_CheckKeyLoaded() validates that the key associated with a loading authorization
+ context is loaded.
+
+ It returns the key pubDataDigest for comparison with the digest of the loading context.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest)
+{
+ TPM_RESULT rc = 0;
+ TPM_KEY_HANDLE_ENTRY *key_handle_entry;
+
+ printf("TPM_LoadContext_CheckKeyLoaded: handle %08x\n", entityHandle);
+ /* get the key associated with entityHandle */
+ /* special case, SRK is not in the key handle list */
+ if (entityHandle == TPM_KH_SRK) {
+ if (tpm_state->tpm_permanent_data.ownerInstalled) {
+ TPM_Digest_Copy(entityDigest,
+ tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest);
+ }
+ else {
+ printf("TPM_LoadContext_CheckKeyLoaded: Error, ownerInstalled is FALSE\n");
+ rc = TPM_NOSRK;
+ }
+ }
+ /* normal case, key is in the key handle list */
+ else {
+ rc = TPM_KeyHandleEntries_GetEntry(&key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ entityHandle);
+ if (rc == 0) {
+ TPM_Digest_Copy(entityDigest, key_handle_entry->key->tpm_store_asymkey->pubDataDigest);
+ }
+ else {
+ printf("TPM_LoadContext_CheckKeyLoaded: Error, key handle %08x not found\n",
+ entityHandle);
+ rc = TPM_BAD_HANDLE;
+ }
+ }
+ return rc;
+}
+
+/* TPM_LoadContext_CheckKeyLoadedByDigest() validates that the key associated with a loading
+ authorization context is loaded.
+
+ It compares the key the pubDataDigest to the digest of the loading context.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest)
+{
+ TPM_RESULT rc = TPM_RETRY; /* any non-zero value will do */
+ size_t start;
+ size_t current;
+ TPM_KEY_HANDLE_ENTRY *key_handle_entry;
+
+ printf("TPM_LoadContext_CheckKeyLoadedByDigest:\n");
+ /* get the key associated with entityDigest */
+ start = 0;
+ /* iterate through all keys in the key handle table */
+ while ((rc != 0) && /* a match sets rc to 0, terminates loop */
+ /* returns TPM_RETRY when at the end of the table, terminates loop */
+ (TPM_KeyHandleEntries_GetNextEntry(&key_handle_entry,
+ &current,
+ tpm_state->tpm_key_handle_entries,
+ start)) == 0) {
+
+
+ start = current + 1;
+ rc = TPM_Digest_Compare(entityDigest,
+ key_handle_entry->key->tpm_store_asymkey->pubDataDigest);
+ }
+ /* if that failed, check the SRK */
+ if (rc != 0) {
+ if (tpm_state->tpm_permanent_data.ownerInstalled) {
+ rc = TPM_Digest_Compare
+ (entityDigest,
+ tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest);
+ }
+ }
+ if (rc != 0) {
+ printf("TPM_LoadContext_CheckKeyLoadedByDigest: "
+ "Error, OSAP or DSAP entityDigest mismatch\n");
+ rc = TPM_RESOURCEMISSING;
+ }
+ return rc;
+}
+
+/* TPM_LoadContext_CheckOwnerLoaded() validates that the owner is loaded.
+
+ It returns the owner authorization for comparison with the digest of the loading context.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest)
+{
+ TPM_RESULT rc = 0;
+
+ printf("TPM_LoadContext_CheckOwnerLoaded:\n");
+ /* verify that an owner is installed */
+ if (rc == 0) {
+ if (!tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_LoadContext_CheckOwnerLoaded: Error, no owner\n");
+ rc = TPM_RESOURCEMISSING;
+ }
+ }
+ if (rc == 0) {
+ TPM_Digest_Copy(entityDigest, tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ return rc;
+}
+
+/* TPM_LoadContext_CheckSrkLoaded() validates that the SRK is loaded.
+
+ It returns the SRK pubDataDigest for comparison with the digest of the loading context.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state,
+ TPM_DIGEST entityDigest)
+{
+ TPM_RESULT rc = 0;
+
+ printf("TPM_LoadContext_CheckSrkLoaded:\n");
+ /* verify that an owner is installed */
+ if (rc == 0) {
+ if (!tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_LoadContext_CheckSrkLoaded: Error, no SRK\n");
+ rc = TPM_RESOURCEMISSING;
+ }
+ }
+ if (rc == 0) {
+ TPM_Digest_Copy(entityDigest,
+ tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest);
+ }
+ return rc;
+}
+
+/* TPM_LoadContext_CheckCounterLoaded() validates that the counter associated with a loading
+ authorization context is loaded.
+
+ It returns the counter authorization for comparison with the digest of the loading context.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest)
+{
+ TPM_RESULT rc = 0;
+ TPM_COUNTER_VALUE *counterValue; /* associated with entityHandle */
+
+ printf("TPM_LoadContext_CheckCounterLoaded: handle %08x\n", entityHandle);
+ if (rc == 0) {
+ rc = TPM_Counters_GetCounterValue(&counterValue,
+ tpm_state->tpm_permanent_data.monotonicCounter,
+ entityHandle);
+ if (rc != 0) {
+ printf("TPM_LoadContext_CheckCounterLoaded: Error, no counter\n");
+ rc = TPM_RESOURCEMISSING;
+ }
+ }
+ if (rc == 0) {
+ TPM_Digest_Copy(entityDigest, counterValue->digest);
+ }
+ return rc;
+}
+
+/* TPM_LoadContext_CheckNvLoaded() validates that the NV space associated with a loading
+ authorization context exists.
+*/
+
+static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state,
+ TPM_HANDLE entityHandle,
+ TPM_DIGEST entityDigest)
+{
+
+ TPM_RESULT rc = 0;
+ TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */
+
+ printf(" TPM_LoadContext_CheckNvLoaded: handle %08x\n", entityHandle);
+ if (rc == 0) {
+ rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive,
+ &(tpm_state->tpm_nv_index_entries),
+ entityHandle);
+ if (rc != 0) {
+ printf("TPM_LoadContext_CheckNvLoaded: Error, no NV at index %08x\n", entityHandle);
+ rc = TPM_RESOURCEMISSING;
+ }
+ }
+ if (rc == 0) {
+ TPM_Digest_Copy(entityDigest, tpm_nv_data_sensitive->digest);
+ }
+ return rc;
+}
+
+/* 21.1 TPM_KeyControlOwner rev 116
+
+ This command controls some attributes of keys that are stored within the TPM key cache.
+
+ 1. Set an internal bit within the key cache that controls some attribute of a loaded key.
+
+ 2.When a key is set to ownerEvict, the key handle value remains the same as long as the key
+ remains ownerEvict. The key handle value persists through TPM_Startup.
+
+ OwnerEvict: If this bit is set to true, this key remains in the TPM non-volatile storage
+ through all TPM_Startup events. The only way to evict this key is for the TPM Owner to
+ execute this command again, setting the owner control bit to false and then executing
+ TPM_FlushSpecific.
+
+ The key handle does not reference an authorized entity and is not validated.
+
+ The check for two remaining key slots ensures that users can load the two keys required to
+ execute many commands. Since only the owner can flush owner evict keys, non-owner commands
+ could be blocked if this test was not performed.
+*/
+
+TPM_RESULT TPM_Process_KeyControlOwner(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; /* The handle of a loaded key. */
+ TPM_PUBKEY pubKey; /* The public key associated with the loaded key */
+ TPM_KEY_CONTROL bitName = 0; /* The name of the bit to be modified */
+ TPM_BOOL bitValue = FALSE; /* The value to set the bit to */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner
+ authentication. */
+ 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 ownerAuth; /* HMAC authorization: key ownerAuth */
+
+ /* 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 authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* entry for keyHandle */
+ TPM_BOOL isSpace;
+ TPM_BOOL oldOwnerEvict; /* original owner evict state */
+ uint16_t ownerEvictCount; /* current number of owner evict keys */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_KeyControlOwner: Ordinal Entry\n");
+ TPM_Pubkey_Init(&pubKey); /* freed @1 */
+ /*
+ 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 pubKey parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_KeyControlOwner: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_Pubkey_Load(&pubKey, &command, &paramSize);
+ }
+ /* get bitName parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&bitName, &command, &paramSize);
+ }
+ /* get bitValue parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load8(&bitValue, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_KeyControlOwner: bitName %08x bitValue %02x\n", bitName, bitValue);
+ }
+ /* 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_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_KeyControlOwner: 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
+ */
+ /* 1. Validate the AuthData using the owner authentication value, on error return TPM_AUTHFAIL
+ */
+ /* get the session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 2. Validate that keyHandle refers to a loaded key, return TPM_INVALID_KEYHANDLE on error. */
+ /* get the key corresponding to the keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ keyHandle);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_KeyControlOwner: Error, key handle not loaded\n");
+ returnCode = TPM_INVALID_KEYHANDLE;
+ }
+ }
+ /* If the keyUsage field of the key indicated by keyHandle does not have the value
+ TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, TPM_KEY_BIND, or TPM_KEY_LEGACY, the TPM
+ must return the error code TPM_INVALID_KEYUSAGE. */
+ if (returnCode == TPM_SUCCESS) {
+ if ((tpm_key_handle_entry->key->keyUsage != TPM_KEY_SIGNING) &&
+ (tpm_key_handle_entry->key->keyUsage != TPM_KEY_STORAGE) &&
+ (tpm_key_handle_entry->key->keyUsage != TPM_KEY_IDENTITY) &&
+ (tpm_key_handle_entry->key->keyUsage != TPM_KEY_BIND) &&
+ (tpm_key_handle_entry->key->keyUsage != TPM_KEY_LEGACY)) {
+ printf("TPM_Process_KeyControlOwner: Error, invalid key keyUsage %04hx\n",
+ tpm_key_handle_entry->key->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 3. Validate that pubKey matches the key held by the TPM pointed to by keyHandle, return
+ TPM_BAD_PARAMETER on mismatch */
+ /* a. This check is added so that virtualization of the keyHandle does not result in attacks, as
+ the keyHandle is not associated with an authorization value */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_ComparePubkey(tpm_key_handle_entry->key, &pubKey);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_KeyControlOwner: Error comparing pubKey\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 4. Validate that bitName is valid, return TPM_BAD_MODE on error. NOTE Valid means a legal
+ TPM_KEY_CONTROL value */
+ if (returnCode == TPM_SUCCESS) {
+ switch(bitName) {
+ /* 5. If bitName == TPM_KEY_CONTROL_OWNER_EVICT */
+ case TPM_KEY_CONTROL_OWNER_EVICT:
+ /* save the old value to determine if NVRAM update is necessary */
+ oldOwnerEvict = tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT;
+ /* a. If bitValue == TRUE */
+ if (bitValue) {
+ printf("TPM_Process_KeyControlOwner: setting key owner evict\n");
+ if (!oldOwnerEvict) { /* if the key is not owner evict */
+ /* i. Verify that after this operation at least two key slots will be present
+ within the TPM that can store any type of key both of which do NOT have the
+ OwnerEvict bit set, on error return TPM_NOSPACE */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_KeyHandleEntries_IsEvictSpace(&isSpace,
+ tpm_state->tpm_key_handle_entries,
+ 2); /* minSpace */
+ if (!isSpace) {
+ printf("TPM_Process_KeyControlOwner: Error, "
+ "Need 2 non-evict slots\n");
+ returnCode = TPM_NOSPACE;
+ }
+ }
+ /* ii. Verify that for this key handle, parentPCRStatus is FALSE and isVolatile
+ is FALSE. Return TPM_BAD_PARAMETER on error. */
+ if (returnCode == TPM_SUCCESS) {
+ if (tpm_key_handle_entry->parentPCRStatus ||
+ tpm_key_handle_entry->key->keyFlags & TPM_ISVOLATILE) {
+ printf("TPM_Process_KeyControlOwner: Error, "
+ "parentPCRStatus or Volatile\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* check the current number of occupied owner evict key slots */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_OwnerEvictGetCount
+ (&ownerEvictCount,
+ tpm_state->tpm_key_handle_entries);
+ }
+ /* check that the number of owner evict key slots will not be exceeded */
+ if (returnCode == TPM_SUCCESS) {
+ if (ownerEvictCount == TPM_OWNER_EVICT_KEY_HANDLES) {
+ printf("TPM_Process_KeyControlOwner: Error, "
+ "no evict space, only %u evict slots\n",
+ TPM_OWNER_EVICT_KEY_HANDLES);
+ returnCode = TPM_NOSPACE;
+ }
+ }
+ /* iii. Set ownerEvict within the internal key storage structure to TRUE. */
+ if (returnCode == TPM_SUCCESS) {
+ tpm_key_handle_entry->keyControl |= TPM_KEY_CONTROL_OWNER_EVICT;
+ }
+ /* if the old value was FALSE, write the entry to NVRAM */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ TRUE, /* write NV */
+ 0); /* no roll back */
+ }
+ }
+ else { /* if the key is already owner evict, nothing to do */
+ printf("TPM_Process_KeyControlOwner: key is already owner evict\n");
+ }
+ }
+ /* b. Else if bitValue == FALSE */
+ else {
+ if (oldOwnerEvict) { /* if the key is currently owner evict */
+ printf("TPM_Process_KeyControlOwner: setting key not owner evict\n");
+ /* i. Set ownerEvict within the internal key storage structure to FALSE. */
+ if (returnCode == TPM_SUCCESS) {
+ tpm_key_handle_entry->keyControl &= ~TPM_KEY_CONTROL_OWNER_EVICT;
+ }
+ /* if the old value was TRUE, delete the entry from NVRAM */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ TRUE, /* write NV */
+ 0); /* no roll back */
+ }
+ }
+ else { /* if the key is already not owner evict, nothing to do */
+ printf("TPM_Process_KeyControlOwner: key is already not owner evict\n");
+ }
+ }
+ break;
+ default:
+ printf("TPM_Process_KeyControlOwner: Invalid bitName %08x\n", bitName);
+ returnCode = TPM_BAD_MODE;
+ break;
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_KeyControlOwner: 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;
+ /* 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) {
+ 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_Pubkey_Delete(&pubKey); /* @1 */
+ return rcf;
+}
+
+/* 27.2 Context management
+
+ The 1.1 context commands were written for specific resource types. The 1.2 commands are generic
+ for all resource types. So the Savexxx commands are replaced by TPM_SaveContext and the LoadXXX
+ commands by TPM_LoadContext.
+*/
+
+/* 27.2.1 TPM_SaveKeyContext rev 87
+
+ SaveKeyContext saves a loaded key outside the TPM. After creation of the key context blob the TPM
+ automatically releases the internal memory used by that key. The format of the key context blob is
+ specific to a TPM.
+*/
+
+TPM_RESULT TPM_Process_SaveKeyContext(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; /* The key which will be kept outside the TPM */
+
+ /* 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_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the key handle */
+ TPM_BOOL isZero; /* contextNonceKey not set yet */
+ TPM_CONTEXT_SENSITIVE contextSensitive;
+ TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */
+ TPM_CONTEXT_BLOB contextBlob;
+ TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_SaveKeyContext: Ordinal Entry\n");
+ TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */
+ TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */
+ TPM_ContextBlob_Init(&contextBlob); /* freed @3 */
+ TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* get keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* 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_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_SaveKeyContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. This command allows saving a loaded key outside the TPM. After creation of the
+ KeyContextBlob, the TPM automatically releases the internal memory used by that key. The
+ format of the key context blob is specific to a TPM.
+
+ 2. A TPM protected capability belonging to the TPM that created a key context blob MUST be
+ the only entity that can interpret the contents of that blob. If a cryptographic technique is
+ used for this purpose, the level of security provided by that technique SHALL be at least as
+ secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a cryptographic
+ technique MUST be generated using the TPM's random number generator. Any symmetric key MUST
+ be used within the power-on session during which it was created, only.
+
+ 3. A key context blob SHALL enable verification of the integrity of the contents of the blob
+ by a TPM protected capability.
+
+ 4. A key context blob SHALL enable verification of the session validity of the contents of
+ the blob by a TPM protected capability. The method SHALL ensure that all key context blobs
+ are rendered invalid if power to the TPM is interrupted.
+ */
+ /* check if the key handle is valid */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveKeyContext: Handle %08x\n", keyHandle);
+ returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ keyHandle);
+ }
+ /* use the contextNonceKey to invalidate a blob at power up */
+ if (returnCode == TPM_SUCCESS) {
+ /* If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */
+ TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey);
+ if (isZero) {
+ /* Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM RNG */
+ returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey);
+ }
+ }
+ /* Create internalData by putting the sensitive part of the resource pointed to by handle into a
+ structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive
+ information of the resource is included in internalData. For a key, the sensitive part is
+ the TPM_STORE_ASYMKEY */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_SENSITIVE\n");
+ returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData),
+ tpm_key_handle_entry,
+ (TPM_STORE_FUNCTION_T)TPM_KeyHandleEntry_Store);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* TPM_CONTEXT_SENSITIVE -> contextNonce */
+ TPM_Nonce_Copy(contextSensitive.contextNonce, tpm_state->tpm_stclear_data.contextNonceKey);
+ /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */
+ printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_BLOB\n");
+ contextBlob.resourceType = TPM_RT_KEY;
+ contextBlob.handle = keyHandle;
+ contextBlob.contextCount = 0;
+ }
+ /* TPM_CONTEXT_BLOB -> sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive);
+ }
+ /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData),
+ &contextSensitive_sbuffer);
+ }
+ /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using
+ TPM_PERMANENT_DATA -> tpmProof as the secret */
+ if (returnCode == TPM_SUCCESS) {
+ /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the
+ HMAC is generated. The result is put back into the structure. */
+ printf("TPM_Process_SaveKeyContext: Digesting TPM_CONTEXT_BLOB\n");
+ returnCode = TPM_HMAC_GenerateStructure
+ (contextBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &contextBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */
+ }
+ /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the
+ result in TPM_CONTEXT_BLOB -> sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now,
+ before the encrypted data is stored there. */
+ TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData));
+ printf("TPM_Process_SaveKeyContext: Encrypting TPM_CONTEXT_SENSITIVE\n");
+ returnCode =
+ TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData),
+ &contextSensitive_sbuffer,
+ tpm_state->tpm_permanent_data.contextKey);
+ }
+ /* serialize TPM_CONTEXT_BLOB */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob);
+ }
+ /* invalidate the key handle and delete the key */
+ if (returnCode == TPM_SUCCESS) {
+ /* free the key resources, free the key itself, and remove entry from the key handle entries
+ list */
+ TPM_KeyHandleEntry_Delete(tpm_key_handle_entry);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_SaveKeyContext: 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 keyContextSize and keyContextBlob */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer);
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */
+ TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */
+ TPM_ContextBlob_Delete(&contextBlob); /* @3 */
+ TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */
+ return rcf;
+}
+
+/* 27.2.2 TPM_LoadKeyContext rev 87
+
+ LoadKeyContext loads a key context blob into the TPM previously retrieved by a SaveKeyContext
+ call. After successful completion the handle returned by this command can be used to access the
+ key.
+*/
+
+TPM_RESULT TPM_Process_LoadKeyContext(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 */
+ uint32_t keyContextSize; /* The size of the following key context blob */
+ TPM_CONTEXT_BLOB keyContextBlob; /* The key context blob */
+
+ /* 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 */
+ unsigned char *stream;
+ uint32_t stream_size;
+ unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */
+ uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */
+ TPM_CONTEXT_SENSITIVE contextSensitive;
+ TPM_KEY_HANDLE_ENTRY *used_key_handle_entry;
+ TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry;
+ TPM_RESULT getRc; /* is the handle value free */
+ TPM_BOOL isSpace;
+ uint32_t index; /* free space index */
+ TPM_BOOL key_added = FALSE; /* key has been added to handle list */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_KEY_HANDLE keyHandle; /* The handle assigned to the key after it has been
+ successfully loaded. */
+
+ printf("TPM_Process_LoadKeyContext: Ordinal Entry\n");
+ TPM_ContextBlob_Init(&keyContextBlob); /* freed @1 */
+ contextSensitiveBuffer = NULL; /* freed @2 */
+ TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */
+ TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get keyContextSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&keyContextSize, &command, &paramSize);
+ }
+ /* get keyContextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&keyContextBlob, &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_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_LoadKeyContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. This command allows loading a key context blob into the TPM previously retrieved by a
+ TPM_SaveKeyContext call. After successful completion the handle returned by this command can
+ be used to access the key.
+
+ 2. The contents of a key context blob SHALL be discarded unless the contents have passed an
+ integrity test. This test SHALL (statistically) prove that the contents of the blob are the
+ same as when the blob was created.
+
+ 3. The contents of a key context blob SHALL be discarded unless the contents have passed a
+ session validity test. This test SHALL (statistically) prove that the blob was created by
+ this TPM during this power-on session.
+ */
+ if (returnCode == TPM_SUCCESS) {
+ if (keyContextBlob.resourceType != TPM_RT_KEY) {
+ printf("TPM_Process_LoadKeyContext: Error, resourceType %08x should be TPM_RT_KEY\n",
+ keyContextBlob.resourceType);
+ returnCode =TPM_BAD_PARAMETER;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n");
+ returnCode =
+ TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */
+ &contextSensitiveBuffer_length, /* length decrypted data */
+ keyContextBlob.sensitiveData.buffer, /* encrypted */
+ keyContextBlob.sensitiveData.size,
+ tpm_state->tpm_permanent_data.contextKey);
+ }
+ /* deserialize TPM_CONTEXT_SENSITIVE */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Creating TPM_CONTEXT_SENSITIVE\n");
+ stream = contextSensitiveBuffer;
+ stream_size = contextSensitiveBuffer_length;
+ returnCode = TPM_ContextSensitive_Load(&contextSensitive, &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Loading TPM_KEY_HANDLE_ENTRY from internalData\n");
+ stream = contextSensitive.internalData.buffer;
+ stream_size = contextSensitive.internalData.size;
+ returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size);
+ }
+ /* check contextNonce */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n");
+ returnCode = TPM_Nonce_Compare(tpm_state->tpm_stclear_data.contextNonceKey,
+ contextSensitive.contextNonce);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Error comparing contextNonceKey\n");
+ returnCode = TPM_BADCONTEXT;
+ }
+ }
+ /* Move decrypted data back to keyContextBlob for integrityDigest check. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Set(&(keyContextBlob.sensitiveData),
+ contextSensitiveBuffer_length, contextSensitiveBuffer);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Checking integrityDigest\n");
+ /* make a copy of integrityDigest, because it needs to be 0 for the HMAC calculation */
+ /* NOTE Done by TPM_HMAC_CheckStructure() */
+ /* b. Set B1 -> integrityDigest to NULL */
+ /* NOTE Done by TPM_HMAC_CheckStructure() */
+ /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof
+ as the HMAC key */
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &keyContextBlob, /* structure */
+ keyContextBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */
+ TPM_BADCONTEXT); /* error code */
+ }
+ /* try to use the saved handle value when possible */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Checking if suggested handle %08x is free\n",
+ keyContextBlob.handle);
+ /* check if the key handle is free */
+ getRc = TPM_KeyHandleEntries_GetEntry(&used_key_handle_entry,
+ tpm_state->tpm_key_handle_entries,
+ keyContextBlob.handle);
+ /* GetEntry TPM_SUCCESS means the handle is already used */
+ if (getRc == TPM_SUCCESS) {
+ keyHandle = 0; /* no suggested handle */
+ }
+ /* not success means that the handle value is not currently used */
+ else {
+ keyHandle = keyContextBlob.handle;
+ }
+ }
+ /* check that there is space in the key handle entries */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Checking for table space\n");
+ TPM_KeyHandleEntries_IsSpace(&isSpace, &index,
+ tpm_state->tpm_key_handle_entries);
+ /* if there is no space, return error */
+ if (!isSpace) {
+ printf("TPM_Process_LoadKeyContext: Error, no room in table\n");
+ returnCode = TPM_RESOURCES;
+ }
+ }
+ /* restore the entity, try to keep the handle as 'handle' */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadKeyContext: Adding entry to table\n");
+ returnCode = TPM_KeyHandleEntries_AddEntry(&keyHandle,
+ FALSE, /* keep handle */
+ tpm_state->tpm_key_handle_entries,
+ &tpm_key_handle_entry);
+ key_added = TRUE;
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_LoadKeyContext: 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) {
+ /* return keyHandle */
+ returnCode = TPM_Sbuffer_Append32(response, keyHandle);
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_ContextBlob_Delete(&keyContextBlob); /* @1 */
+ free(contextSensitiveBuffer); /* @2 */
+ TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */
+ /* if there was a failure, roll back */
+ if ((rcf != 0) || (returnCode != TPM_SUCCESS)) {
+ TPM_Key_Delete(tpm_key_handle_entry.key); /* @5 */
+ free(tpm_key_handle_entry.key); /* @5 */
+ if (key_added) {
+ /* if there was a failure and a key was stored in the handle list, free the handle.
+ Ignore errors, since only one error code can be returned. */
+ TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, keyHandle);
+ }
+ }
+ return rcf;
+}
+
+/* 27.2.3 TPM_SaveAuthContext rev 87
+
+ SaveAuthContext saves a loaded authorization session outside the TPM. After creation of the
+ authorization context blob, the TPM automatically releases the internal memory used by that
+ session. The format of the authorization context blob is specific to a TPM.
+*/
+
+TPM_RESULT TPM_Process_SaveAuthContext(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_AUTHHANDLE authHandle; /* Authorization session which will be kept outside the TPM
+ */
+
+ /* 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_AUTH_SESSION_DATA *tpm_auth_session_data; /* session table entry for the handle */
+ TPM_BOOL isZero; /* contextNonceSession not set yet */
+ TPM_STCLEAR_DATA *v1StClearData = NULL;
+ uint32_t contextIndex = 0; /* free index in context list */
+ uint32_t space; /* free space in context list */
+ TPM_CONTEXT_SENSITIVE contextSensitive;
+ TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */
+ TPM_CONTEXT_BLOB contextBlob;
+ TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_SaveAuthContext: Ordinal Entry\n");
+ TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */
+ TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */
+ TPM_ContextBlob_Init(&contextBlob); /* freed @3 */
+ TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* get authHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&authHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveAuthContext: authHandle %08x\n", authHandle);
+ }
+ /* 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_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_SaveAuthContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* This command allows saving a loaded authorization session outside the TPM. After creation of
+ the authContextBlob, the TPM automatically releases the internal memory used by that
+ session. The format of the authorization context blob is specific to a TPM.
+
+ A TPM protected capability belonging to the TPM that created an authorization context blob
+ MUST be the only entity that can interpret the contents of that blob. If a cryptographic
+ technique is used for this purpose, the level of security provided by that technique SHALL be
+ at least as secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a
+ cryptographic technique MUST be generated using the TPM's random number generator. Any
+ symmetric key MUST be used within the power-on session during which it was created, only.
+
+ An authorization context blob SHALL enable verification of the integrity of the contents of
+ the blob by a TPM protected capability.
+
+ An authorization context blob SHALL enable verification of the session validity of the
+ contents of the blob by a TPM protected capability. The method SHALL ensure that all
+ authorization context blobs are rendered invalid if power to the TPM is interrupted.
+ */
+ /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ v1StClearData = &(tpm_state->tpm_stclear_data);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveAuthContext: Handle %08x\n", authHandle);
+ returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data,
+ v1StClearData->authSessions,
+ authHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* If TPM_STANY_DATA -> contextNonceSession is NULLS */
+ TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession);
+ if (isZero) {
+ /* Set TPM_STANY_DATA -> contextNonceSession to the next value from the TPM RNG */
+ returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession);
+ }
+ }
+ /* Create internalData by putting the sensitive part of the resource pointed to by handle into a
+ structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive
+ information of the resource is included in internalData. For a session, the entire structure
+ can fit in the sensitive part. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_SENSITIVE\n");
+ returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData),
+ tpm_auth_session_data,
+ (TPM_STORE_FUNCTION_T)TPM_AuthSessionData_Store);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* TPM_CONTEXT_SENSITIVE -> contextNonce */
+ TPM_Nonce_Copy(contextSensitive.contextNonce, v1StClearData->contextNonceSession);
+ /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */
+ printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_BLOB\n");
+ contextBlob.resourceType = TPM_RT_AUTH;
+ contextBlob.handle = authHandle;
+ TPM_Digest_Init(contextBlob.integrityDigest);
+ }
+ /* TPM_CONTEXT_BLOB -> sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive);
+ }
+ /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData),
+ &contextSensitive_sbuffer);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveAuthContext: Processing session context count\n");
+ /* a. If V1 -> contextCount > 2^32-2 then */
+ if (v1StClearData->contextCount > 0xfffffffe) {
+ /* i. Return with TPM_TOOMANYCONTEXTS */
+ printf("TPM_Process_SaveAuthContext: Error, too many contexts\n");
+ returnCode = TPM_TOOMANYCONTEXTS;
+ }
+ }
+ /* b. Else */
+ if (returnCode == TPM_SUCCESS) {
+ /* i. Increment V1 -> contextCount by 1 */
+ v1StClearData->contextCount++;
+ /* ii. Validate that the TPM can still manage the new count value */
+ /* (1) If the distance between the oldest saved context and the contextCount is
+ too large return TPM_CONTEXT_GAP */
+ /* Since contextCount is uint32_t, this is not applicable here. From email: Does the
+ TPM have the ability to keep track of the context delta. It is possible to keep
+ track of things with just a byte or so internally, if this is done a gap of
+ greater than 2^16 or so might be too large, hence the context gap message */
+ }
+ /* iii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not
+ found exit with TPM_NOCONTEXTSPACE */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList);
+ if (space == 0) {
+ printf("TPM_Process_SaveAuthContext: Error, no space in context list\n");
+ returnCode = TPM_NOCONTEXTSPACE;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */
+ v1StClearData->contextList[contextIndex] = v1StClearData->contextCount;
+ /* v. Set B1 -> contextCount to V1 -> contextCount */
+ contextBlob.contextCount = v1StClearData->contextCount;
+ }
+ /* c. The TPM MUST invalidate all information regarding the resource except for information
+ needed for reloading */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, authHandle);
+ }
+ /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using
+ TPM_PERMANENT_DATA -> tpmProof as the secret */
+ if (returnCode == TPM_SUCCESS) {
+ /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the
+ HMAC is generated. The result is put back into the structure. */
+ printf("TPM_Process_SaveAuthContext: Digesting TPM_CONTEXT_BLOB\n");
+ returnCode = TPM_HMAC_GenerateStructure
+ (contextBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &contextBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */
+ }
+ /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the
+ result in TPM_CONTEXT_BLOB -> sensitiveData */
+ if (returnCode == TPM_SUCCESS) {
+ /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now,
+ before the encrypted data is stored there. */
+ TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData));
+ printf("TPM_Process_SaveAuthContext: Encrypting TPM_CONTEXT_SENSITIVE\n");
+ returnCode =
+ TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData),
+ &contextSensitive_sbuffer,
+ tpm_state->tpm_permanent_data.contextKey);
+ }
+ /* serialize TPM_CONTEXT_BLOB */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_SaveAuthContext: 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 authContextSize and authContextBlob */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer);
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */
+ TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */
+ TPM_ContextBlob_Delete(&contextBlob); /* @3 */
+ TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */
+ return rcf;
+}
+
+/* 27.2.4 TPM_LoadAuthContext rev 106
+
+ LoadAuthContext loads an authorization context blob into the TPM previously retrieved by a
+ SaveAuthContext call. After successful completion, the handle returned by this command can be used
+ to access the authorization session.
+*/
+
+TPM_RESULT TPM_Process_LoadAuthContext(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 */
+ uint32_t authContextSize; /* The size of the following auth context blob */
+ TPM_CONTEXT_BLOB authContextBlob; /* The auth context blob */
+
+ /* 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 */
+ unsigned char *stream;
+ uint32_t stream_size;
+ unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */
+ uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */
+ TPM_CONTEXT_SENSITIVE contextSensitive;
+ TPM_AUTH_SESSION_DATA tpm_auth_session_data;
+ TPM_AUTH_SESSION_DATA *used_auth_session_data;
+ TPM_RESULT getRc; /* is the handle value free */
+ TPM_BOOL isSpace;
+ uint32_t index; /* free space index */
+ TPM_BOOL auth_session_added = FALSE; /* session key has been added to handle list */
+ TPM_STCLEAR_DATA *v1StClearData = NULL;
+ uint32_t contextIndex;
+ TPM_DIGEST entityDigest; /* digest of the entity used to set up the
+ OSAP or DSAP session */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_KEY_HANDLE authHandle; /* The handle assigned to the authorization session after it
+ has been successfully loaded. */
+
+ printf("TPM_Process_LoadAuthContext: Ordinal Entry\n");
+ TPM_ContextBlob_Init(&authContextBlob); /* freed @1 */
+ contextSensitiveBuffer = NULL; /* freed @2 */
+ TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */
+ TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get authContextSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&authContextSize, &command, &paramSize);
+ }
+ /* get authContextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&authContextBlob, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: handle %08x\n", authContextBlob.handle);
+ }
+ /* 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_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_LoadAuthContext: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* This command allows loading an authorization context blob into the TPM previously retrieved
+ by a TPM_SaveAuthContext call. After successful completion, the handle returned by this
+ command can be used to access the authorization session.
+
+ The contents of an authorization context blob SHALL be discarded unless the contents have
+ passed an integrity test. This test SHALL (statistically) prove that the contents of the blob
+ are the same as when the blob was created.
+
+ The contents of an authorization context blob SHALL be discarded unless the contents have
+ passed a session validity test. This test SHALL (statistically) prove that the blob was
+ created by this TPM during this power-on session.
+
+ For an OSAP authorization context blob referring to a key, verify that the key linked to this
+ session is resident in the TPM.
+ */
+ if (returnCode == TPM_SUCCESS) {
+ /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */
+ v1StClearData = &(tpm_state->tpm_stclear_data);
+ if (authContextBlob.resourceType != TPM_RT_AUTH) {
+ printf("TPM_Process_LoadAuthContext: Error, resourceType %08x should be TPM_RT_AUTH\n",
+ authContextBlob.resourceType);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n");
+ returnCode =
+ TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */
+ &contextSensitiveBuffer_length, /* length decrypted data */
+ authContextBlob.sensitiveData.buffer, /* encrypted */
+ authContextBlob.sensitiveData.size,
+ tpm_state->tpm_permanent_data.contextKey);
+ }
+ /* deserialize TPM_CONTEXT_SENSITIVE */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Creating TPM_CONTEXT_SENSITIVE\n");
+ stream = contextSensitiveBuffer;
+ stream_size = contextSensitiveBuffer_length;
+ returnCode = TPM_ContextSensitive_Load(&contextSensitive,
+ &stream,
+ &stream_size);
+ }
+ /* Parse the TPM_CONTEXT_SENSITIVE -> internalData to TPM_AUTH_SESSION_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Loading TPM_AUTH_SESSION_DATA from internalData\n");
+ stream = contextSensitive.internalData.buffer;
+ stream_size = contextSensitive.internalData.size;
+ returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size);
+ }
+ /* check contextNonce */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: protocolID %04x entityTypeByte %02x\n",
+ tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte);
+ printf("TPM_Process_LoadAuthContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n");
+ returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession,
+ contextSensitive.contextNonce);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Error comparing contextNonceSession\n");
+ returnCode = TPM_BADCONTEXT;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) ||
+ (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) {
+ /* check that the entity is loaded, and that the entity's digest equals that of the OSAP
+ or DSAP session */
+ switch (tpm_auth_session_data.entityTypeByte) {
+ case TPM_ET_OWNER:
+ printf("TPM_Process_LoadAuthContext: Owner OSAP/DSAP session\n");
+ /* check for owner */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state, entityDigest);
+ }
+ /* compare entity digest */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode= TPM_Digest_Compare(entityDigest,
+ tpm_auth_session_data.entityDigest);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: "
+ "Error, OSAP or DSAP entityDigest mismatch\n");
+ returnCode = TPM_RESOURCEMISSING;
+ }
+ }
+ break;
+ case TPM_ET_SRK:
+ printf("TPM_Process_LoadAuthContext: SRK OSAP/DSAP session\n");
+ /* check for SRK */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state, entityDigest);
+ }
+ /* compare entity digest */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode= TPM_Digest_Compare(entityDigest,
+ tpm_auth_session_data.entityDigest);
+ if (returnCode != TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: "
+ "Error, OSAP or DSAP entityDigest mismatch\n");
+ returnCode = TPM_RESOURCEMISSING;
+ }
+ }
+ break;
+ case TPM_ET_KEYHANDLE:
+ printf("TPM_Process_LoadAuthContext: Key OSAP/DSAP session\n");
+ /* for keys */
+ returnCode =
+ TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state,
+ tpm_auth_session_data.entityDigest);
+ break;
+ case TPM_ET_COUNTER:
+ printf("TPM_Process_LoadAuthContext: Counter OSAP/DSAP session\n");
+#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no counter */
+ returnCode =
+ TPM_LoadContext_CheckCounterLoaded(tpm_state,
+ entityHandle,
+ entityDigest);
+#endif
+ break;
+ case TPM_ET_NV:
+ printf("TPM_Process_LoadAuthContext: NV OSAP/DSAP session\n");
+#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no NV space */
+ returnCode =
+ TPM_LoadContext_CheckNvLoaded(tpm_state,
+ entityHandle,
+ entityDigest);
+#endif
+ break;
+ default:
+ printf("TPM_Process_LoadAuthContext: Error, invalid session entityType %02x\n",
+ tpm_auth_session_data.entityTypeByte);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ break;
+ }
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Checking integrityDigest\n");
+ /* b. Set B1 -> integrityDigest to NULL */
+ /* NOTE Done by TPM_HMAC_CheckStructure() */
+ /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */
+ returnCode = TPM_SizedBuffer_Set(&(authContextBlob.sensitiveData),
+ contextSensitiveBuffer_length, contextSensitiveBuffer);
+ /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof
+ as the HMAC key */
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &authContextBlob, /* structure */
+ authContextBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */
+ TPM_BADCONTEXT); /* error code */
+ }
+ /* try to use the saved handle value when possible */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Checking if suggested handle %08x is free\n",
+ authContextBlob.handle);
+ /* check if the auth handle is free */
+ getRc = TPM_AuthSessions_GetEntry(&used_auth_session_data,
+ tpm_state->tpm_stclear_data.authSessions,
+ authContextBlob.handle);
+ /* GetEntry TPM_SUCCESS means the handle is already used */
+ if (getRc == TPM_SUCCESS) {
+ authHandle = 0; /* no suggested handle */
+ }
+ /* not success means that the handle value is not currently used */
+ else {
+ authHandle = authContextBlob.handle;
+ }
+ }
+ /* check that there is space in the authorization handle entries */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Checking for table space\n");
+ TPM_AuthSessions_IsSpace(&isSpace, &index,
+ tpm_state->tpm_stclear_data.authSessions);
+ /* if there is no space, return error */
+ if (!isSpace) {
+ printf("TPM_Process_LoadAuthContext: Error, no room in table\n");
+ TPM_AuthSessions_Trace(tpm_state->tpm_stclear_data.authSessions);
+ returnCode = TPM_RESOURCES;
+ }
+ }
+ /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 ->
+ TPM_CONTEXT_BLOB -> contextCount */
+ /* b. If not found then return TPM_BADCONTEXT */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadAuthContext: Checking contextCount\n");
+ returnCode = TPM_ContextList_GetEntry(&contextIndex,
+ v1StClearData->contextList,
+ authContextBlob.contextCount);
+ }
+ /* c. Set V1 -> contextList[contextIndex] to 0 */
+ if (returnCode == TPM_SUCCESS) {
+ v1StClearData->contextList[contextIndex] = 0;
+ }
+ /* restore the entity, try to keep the handle as 'handle' */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_AddEntry(&authHandle, /* input/output */
+ FALSE, /* keepHandle */
+ v1StClearData->authSessions,
+ &tpm_auth_session_data);
+ auth_session_added = TRUE;
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_LoadAuthContext: 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) {
+ /* return authHandle */
+ returnCode = TPM_Sbuffer_Append32(response, authHandle);
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 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 */
+ }
+ /* 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);
+ }
+ /*
+ cleanup
+ */
+ TPM_ContextBlob_Delete(&authContextBlob); /* @1 */
+ free(contextSensitiveBuffer); /* @2 */
+ TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */
+ TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */
+ /* if there was a failure, roll back */
+ if ((rcf != 0) || (returnCode != TPM_SUCCESS)) {
+ if (auth_session_added) {
+ TPM_AuthSessionData_Delete(&tpm_auth_session_data);
+ }
+ }
+ return rcf;
+}