diff options
Diffstat (limited to 'src/tpm12/tpm_ticks.c')
-rw-r--r-- | src/tpm12/tpm_ticks.c | 913 |
1 files changed, 913 insertions, 0 deletions
diff --git a/src/tpm12/tpm_ticks.c b/src/tpm12/tpm_ticks.c new file mode 100644 index 0000000..c8dc58b --- /dev/null +++ b/src/tpm12/tpm_ticks.c @@ -0,0 +1,913 @@ +/********************************************************************************/ +/* */ +/* Tick Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ticks.c 4526 2011-03-24 21:14:42Z 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 <string.h> +#include <stdio.h> + +#include "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_structures.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_time.h" + +#include "tpm_ticks.h" + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec); +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower); + +/* + UINT64 for currentTicks + + Internally, the UINT64 is stored as sec || usec. This makes calculations easy since TPM_GetTimeOfDay + returns those structure elements. + + The TPM_Uint64_Store() function, the public interface, converts this to a true 64 bit integer. +*/ + +/* TPM_Uint64_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Uint64_Init(TPM_UINT64 *tpm_uint64) +{ + printf(" TPM_Uint64_Init:\n"); + tpm_uint64->sec = 0; + tpm_uint64->usec = 0; + return; +} + +/* TPM_Uint64_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + This function does the conversion from a 64 bit usec to sec / usec. +*/ + +TPM_RESULT TPM_Uint64_Load(TPM_UINT64 *tpm_uint64, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Load:\n"); + /* load upper */ + if (rc == 0) { + rc = TPM_Load32(&upper, stream, stream_size); + } + /* load lower */ + if (rc == 0) { + rc = TPM_Load32(&lower, stream, stream_size); + } + /* convert from 64 bit usec to sec, usec */ + if (rc == 0) { + TPM_Uint64_ConvertTo(&(tpm_uint64->sec), + &(tpm_uint64->usec), + upper, + lower); + } + return rc; +} + +/* TPM_Uint64_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This function does the conversion from sec / usec to a 64 bit usec. +*/ + +TPM_RESULT TPM_Uint64_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_UINT64 *tpm_uint64) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Store:\n"); + /* store upper */ + if (rc == 0) { + /* convert to 64 bit number */ + TPM_Uint64_ConvertFrom(&upper, &lower, tpm_uint64->sec, tpm_uint64->usec); + rc = TPM_Sbuffer_Append32(sbuffer, upper); + } + /* store lower */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, lower); + } + return rc; +} + +void TPM_Uint64_Copy(TPM_UINT64 *dest, + const TPM_UINT64 *src) +{ + printf(" TPM_Uint64_Copy:\n"); + dest->sec = src->sec; + dest->usec = src->usec; + return; +} + +/* TPM_Uint64_ConvertFrom() does the calculation result = sec * 1000000 + usec and splits the result + into two uint32_t's. + + This may not be portable if the compiler does not support long long. +*/ + +/* TPM_Uint64_ConvertTo() does the calculation uint32_t || uint32_t to sec and usec. + + This may not be portable if the compiler does not support long long. +*/ + +#if defined(TPM_POSIX) || defined(TPM_SYSTEM_P) + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec) +{ + long long result; + + printf(" TPM_Uint64_ConvertFrom: sec %u, usec %u\n", sec, usec); + result = (sec * 1000000LL) + (long long)usec; + printf(" TPM_Uint64_ConvertFrom: Result usec %llu, %llx\n", result, result); + *upper = (result >> 32) & 0xffffffff; + *lower = result & 0xffffffff; + printf(" TPM_Uint64_ConvertFrom: Upper %u, %x\n", *upper, *upper); + printf(" TPM_Uint64_ConvertFrom: Lower %u, %x\n", *lower, *lower); + return; +} + +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower) +{ + long long result; + + printf(" TPM_Uint64_ConvertTo: Upper %u, %x\n", upper, upper); + printf(" TPM_Uint64_ConvertTo: Lower %u, %x\n", lower, lower); + result = ((long long)upper << 32) | (long long)lower; + printf(" TPM_Uint64_ConvertTo: Result usec %llu, %llx\n", result, result); + *sec = result / 1000000LL; + *usec = result % 1000000LL; + printf(" TPM_Uint64_ConvertTo: sec %u, usec %u\n", *sec, *usec); + return; +} + +#endif + + +TPM_RESULT TPM_Uint64_Test() +{ + TPM_RESULT rc = 0; + TPM_UINT64 uint64In; + TPM_UINT64 uint64Out; + TPM_STORE_BUFFER sbuffer; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Uint64_Test\n"); + TPM_Sbuffer_Init(&sbuffer); + uint64In.sec = 12345678; + uint64In.usec = 781234; + + if (rc == 0) { + rc = TPM_Uint64_Store(&sbuffer, &uint64In); + } + if (rc == 0) { + TPM_Sbuffer_Get(&sbuffer, (const unsigned char **)&stream, &stream_size); + rc = TPM_Uint64_Load(&uint64Out, &stream, &stream_size); + } + if (rc == 0) { + if ((uint64In.sec != uint64Out.sec) || + (uint64In.usec != uint64Out.usec)) { + printf("TPM_Uint64_Test: Error (fatal)\n"); + rc = TPM_FAILEDSELFTEST; + } + } + TPM_Sbuffer_Delete(&sbuffer); + return rc; +} + +/* + TPM_CURRENT_TICKS +*/ + +/* TPM_CurrentTicks_Init() initializes the tick structure + +*/ + +void TPM_CurrentTicks_Init(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + printf(" TPM_CurrentTicks_Init:\n"); + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + tpm_current_ticks->tickRate = TPM_TICK_RATE; + TPM_Nonce_Init(tpm_current_ticks->tickNonce); + TPM_Uint64_Init(&(tpm_current_ticks->initialTime)); + return; +} + +/* TPM_CurrentTicks_Start() sets the initialTime member to the + current time of day. + + It assumes TPM_CurrentTicks_Init() has been called +*/ + +TPM_RESULT TPM_CurrentTicks_Start(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Start:\n"); + if (rc == 0) { + /* current is relative to the initial value, and is always 0 */ + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + /* save the current time */ + rc = TPM_GetTimeOfDay(&(tpm_current_ticks->initialTime.sec), + &(tpm_current_ticks->initialTime.usec)); + } + if (rc == 0) { + tpm_current_ticks->tickRate = TPM_TICK_RATE; + rc = TPM_Nonce_Generate(tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_LoadAll() loads the standard TCG structure plus the SW TPM members + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CurrentTicks_Init() +*/ + +TPM_RESULT TPM_CurrentTicks_LoadAll(TPM_CURRENT_TICKS *tpm_current_ticks, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_LoadAll:\n"); + /* load tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CURRENT_TICKS, stream, stream_size); + } + /* load currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->currentTicks), stream, stream_size); + } + /* load tickRate */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_current_ticks->tickRate), stream, stream_size); + } + /* load tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_current_ticks->tickNonce, stream, stream_size); + } + /* load initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->initialTime), stream, stream_size); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CURRENT_TICKS); + } + /* store currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->currentTicks)); + } + /* store tickRate */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_current_ticks->tickRate); + } + /* store tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure plus the SW TPM members + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_StoreAll(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_StoreAll:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_CurrentTicks_Store(sbuffer, tpm_current_ticks); + } + /* store initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->initialTime)); + } + return rc; +} + +/* TPM_CurrentTicks_Update() updates the currentTicks member of TPM_CURRENT_TICKS + relative to the initial time + +*/ + +TPM_RESULT TPM_CurrentTicks_Update(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + uint32_t currentTimeSec; + uint32_t currentTimeUsec; + + printf(" TPM_CurrentTicks_Update: Initial %u sec %u usec\n", + tpm_current_ticks->initialTime.sec, tpm_current_ticks->initialTime.usec); + /* get the current time of day */ + if (rc == 0) { + rc = TPM_GetTimeOfDay(¤tTimeSec, ¤tTimeUsec); + } + /* Calculate: + currentTimeSec currentTimeUsec + - initialTimeSec initialTimeUsec + */ + if (rc == 0) { + /* case 1: no borrow */ + if (currentTimeUsec >= tpm_current_ticks->initialTime.usec) { + /* subtract usec */ + tpm_current_ticks->currentTicks.usec = currentTimeUsec - + tpm_current_ticks->initialTime.usec; + + /* check that time went forward */ + if (currentTimeSec >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + /* case 2: borrow */ + else { + /* subtract usec with borrow */ + tpm_current_ticks->currentTicks.usec = 1000000 + currentTimeUsec - + tpm_current_ticks->initialTime.usec; + /* check that time went forward, with borrow */ + if ((currentTimeSec - 1) >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - 1 - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + } + if (rc == 0) { + printf(" TPM_CurrentTicks_Update: Ticks %u sec %u usec\n", + tpm_current_ticks->currentTicks.sec, + tpm_current_ticks->currentTicks.usec); + } + return rc; +} + +/* TPM_CurrentTicks_Copy() copies the 'src' to 'dest' + +*/ + +void TPM_CurrentTicks_Copy(TPM_CURRENT_TICKS *dest, + TPM_CURRENT_TICKS *src) +{ + printf(" TPM_CurrentTicks_Copy:\n"); + TPM_Uint64_Copy(&(dest->currentTicks), &(src->currentTicks)); + dest->tickRate = src->tickRate; + TPM_Nonce_Copy(dest->tickNonce, src->tickNonce); + TPM_Uint64_Copy(&(dest->initialTime), &(src->initialTime)); + return; +} + +/* + Processing Functions +*/ + +/* 23. Timing Ticks rev 87 + + The TPM timing ticks are always available for use. The association of timing ticks to actual time + is a protocol that occurs outside of the TPM. See the design document for details. + + The setting of the clock type variable is a one time operation that allows the TPM to be + configured to the type of platform that is installed on. + + The ability for the TPM to continue to increment the timer ticks across power cycles of the + platform is a TPM and platform manufacturer decision. +*/ + +/* 23.1 TPM_GetTicks rev 87 + + This command returns the current tick count of the TPM. + + This command returns the current time held in the TPM. It is the responsibility of the external + system to maintain any relation between this time and a UTC value or local real time value. +*/ + +TPM_RESULT TPM_Process_GetTicks(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 */ + + /* 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; + TPM_CURRENT_TICKS *t1CurrentTicks = NULL; /* The current time held in the TPM */ + + printf("TPM_Process_GetTicks: 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_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetTicks: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. Set T1 to the internal TPM_CURRENT_TICKS structure */ + t1CurrentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(t1CurrentTicks); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetTicks: 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; + /* 2. Return T1 as currentTime. */ + returnCode = TPM_CurrentTicks_Store(response, t1CurrentTicks); + /* 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; +} + +/* 23.2 TPM_TickStampBlob rev 101 + + This command applies a time stamp to the passed blob. The TPM makes no representation regarding + the blob merely that the blob was present at the TPM at the time indicated. + + The function performs a digital signature on the hash of digestToStamp and the current tick + count. + + It is the responsibility of the external system to maintain any relation between tick count and a + UTC value or local real time value. + +*/ + +TPM_RESULT TPM_Process_TickStampBlob(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 keyHandle identifier of a loaded key that can perform digital + signatures. */ + TPM_NONCE antiReplay; /* Anti replay value added to signature */ + TPM_DIGEST digestToStamp; /* The digest to perform the tick stamp on */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle authorization + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_KEY *sigKey; /* signing key */ + TPM_SECRET *keyUsageAuth; + TPM_SECRET *hmacKey; + TPM_BOOL parentPCRStatus; + TPM_SIGN_INFO h1SignInfo; + TPM_STORE_BUFFER h2Data; + TPM_STORE_BUFFER h1sbuffer; /* serialization of h1SignInfo */ + TPM_DIGEST h3Digest; /* digest to be signed */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_TickStampBlob: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* freed @1 */ + TPM_SignInfo_Init(&h1SignInfo); /* freed @2 */ + TPM_Sbuffer_Init(&h2Data); /* freed @3 */ + TPM_Sbuffer_Init(&h1sbuffer); /* freed @4 */ + /* + 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 antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get digestToStamp parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TickStampBlob: antiReplay", antiReplay); + returnCode = TPM_Digest_Load(digestToStamp, &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) { + TPM_PrintFour("TPM_Process_TickStampBlob: digestToStamp", digestToStamp); + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_TickStampBlob: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TickStampBlob: 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 + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_TickStampBlob: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Checking key properties\n"); + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_IDENTITY) && + (sigKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_TickStampBlob: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_TickStampBlob: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + /* 4. If TPM_STCLEAR_DATA -> currentTicks is not properly initialized */ + /* a. Initialize the TPM_STCLEAR_DATA -> currentTicks */ + /* NOTE: Always initialized */ + /* 5. Create T1, a TPM_CURRENT_TICKS structure. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Creating TPM_CURRENT_TICKS structure\n"); + currentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ + printf("TPM_Process_TickStampBlob: Creating TPM_SIGN_INFO structure\n"); + /* NOTE: Done by TPM_SignInfo_Init() */ + /* a. Set H1 -> fixed to 'TSTP' */ + memcpy(h1SignInfo.fixed, "TSTP", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set H1 -> replay to antiReplay */ + TPM_Nonce_Copy(h1SignInfo.replay, antiReplay ); + /* c. Create H2 the concatenation of digestToStamp || T1 */ + /* add digestToStamp */ + returnCode = TPM_Digest_Store(&h2Data, digestToStamp); + } + /* add T1 (currentTicks) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(&h2Data, currentTicks); + } + /* d. Set H1 -> dataLen to the length of H2 */ + /* e. Set H1 -> data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(h1SignInfo.data), &h2Data); + } + /* 7. The TPM computes the signature, sig, using the key referenced by keyHandle, using SHA-1 of + H1 as the information to be signed */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Digesting TPM_SIGN_INFO structure\n"); + returnCode = TPM_SHA1_GenerateStructure(h3Digest, &h1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Signing TPM_SIGN_INFO digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h3Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TickStampBlob: 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; + /* 7. The TPM returns T1 as currentTicks parameter */ + returnCode = TPM_CurrentTicks_Store(response, currentTicks); + } + /* 6. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&sig); /* @1 */ + TPM_SignInfo_Delete(&h1SignInfo); /* @2 */ + TPM_Sbuffer_Delete(&h2Data); /* @3 */ + TPM_Sbuffer_Delete(&h1sbuffer); /* @4 */ + return rcf; +} + |