diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
commit | 92cccad89d1c12b39165d5f0ed7ccd2d44965a1a (patch) | |
tree | f59a2764cd8c50959050a428bd8fc935138df750 /src/tpm12/tpm_session.c | |
parent | Initial commit. (diff) | |
download | libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.tar.xz libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.zip |
Adding upstream version 0.9.2.upstream/0.9.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tpm12/tpm_session.c')
-rw-r--r-- | src/tpm12/tpm_session.c | 5540 |
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, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + /* get nonceOddOSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityValue %08x\n", entityValue); + returnCode = TPM_Nonce_Load(nonceOddOSAP, &command, ¶mSize); + } + /* 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, ¶mSize); + } + /* get keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get nonceOddDSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(nonceOddDSAP, &command, ¶mSize); + } + /* 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get label */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: resourceType %08x\n", resourceType); + returnCode = TPM_Loadn(label, TPM_CONTEXT_LABEL_SIZE, &command, ¶mSize); + } + 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get contextSize parameter (redundant, not used) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: keepHandle %02x\n", keepHandle); + returnCode = TPM_Load32(&contextSize, &command, ¶mSize); + } + /* get contextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&b1ContextBlob, &command, ¶mSize); + } + /* 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, + ¤t, + 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get bitName parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bitName, &command, ¶mSize); + } + /* get bitValue parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load8(&bitValue, &command, ¶mSize); + } + 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, ¶mSize); + } + 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get keyContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&keyContextBlob, &command, ¶mSize); + } + /* 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get authContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&authContextBlob, &command, ¶mSize); + } + 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; +} |