/********************************************************************************/ /* */ /* Counter Handler */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: tpm_counter.c 4539 2011-04-04 21:44:22Z 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 #include #include "tpm_auth.h" #include "tpm_cryptoh.h" #include "tpm_debug.h" #include "tpm_digest.h" #include "tpm_error.h" #include "tpm_io.h" #include "tpm_permanent.h" #include "tpm_process.h" #include "tpm_secret.h" #include "tpm_counter.h" /* Monotonic Counter Resource Handling */ /* TPM_Counters_Init() initializes the monotonic counters */ void TPM_Counters_Init(TPM_COUNTER_VALUE *monotonicCounters) { uint32_t i; for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { TPM_CounterValue_Init(&(monotonicCounters[i])); } return; } /* TPM_Counters_Load() loads the monotonic counters deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes */ TPM_RESULT TPM_Counters_Load(TPM_COUNTER_VALUE *monotonicCounters, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; uint32_t i; /* load the counters */ for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { rc = TPM_CounterValue_Load(&(monotonicCounters[i]), stream, stream_size); } return rc; } TPM_RESULT TPM_Counters_Store(TPM_STORE_BUFFER *sbuffer, TPM_COUNTER_VALUE *monotonicCounters) { TPM_RESULT rc = 0; uint32_t i; /* store the counters */ for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { rc = TPM_CounterValue_Store(sbuffer, &(monotonicCounters[i])); } return rc; } /* TPM_Counters_StoreHandles() stores a count of the created counters and a list of created counter handles. */ TPM_RESULT TPM_Counters_StoreHandles(TPM_STORE_BUFFER *sbuffer, TPM_COUNTER_VALUE *monotonicCounters) { TPM_RESULT rc = 0; uint16_t loaded; uint32_t i; printf(" TPM_Counters_StoreHandles:\n"); if (rc == 0) { loaded = 0; /* count the number of loaded counters */ for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { if ((monotonicCounters[i]).valid) { loaded++; } } /* store created handle count */ rc = TPM_Sbuffer_Append16(sbuffer, loaded); } for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { if ((monotonicCounters[i]).valid) { /* the handle is just the index */ rc = TPM_Sbuffer_Append32(sbuffer, i); /* store it */ } } return rc; } /* TPM_Counters_GetSpace() returns the number of unused monotonicCounters. */ void TPM_Counters_GetSpace(uint32_t *space, TPM_COUNTER_VALUE *monotonicCounters) { uint32_t i; printf(" TPM_Counters_GetSpace:\n"); for (*space = 0 , i = 0 ; i < TPM_MIN_COUNTERS ; i++) { if (!(monotonicCounters[i]).valid) { (*space)++; } } return; } /* TPM_Counters_GetNewHandle() checks for space in the monotonicCounters table. If there is space, it returns a TPM_COUNTER_VALUE entry in 'tpm_counter_value' and its handle in 'countID'. The entry is marked 'valid'. Returns TPM_RESOURCES if there is no space in the sessions table. monotonicCounters is not altered on error. */ TPM_RESULT TPM_Counters_GetNewHandle(TPM_COUNTER_VALUE **tpm_counter_value, TPM_COUNT_ID *countID, TPM_COUNTER_VALUE *monotonicCounters) { TPM_RESULT rc = 0; TPM_BOOL is_space; printf(" TPM_Counters_GetNewHandle:\n"); for (*countID = 0, is_space = FALSE ; *countID < TPM_MIN_COUNTERS ; (*countID)++) { if (!(monotonicCounters[*countID]).valid) { is_space = TRUE; break; } } /* NOTE: According to TPMWG email, TPM_COUNT_ID can be an index */ if (is_space) { printf(" TPM_Counters_GetNewHandle: Assigned handle %u\n", *countID); *tpm_counter_value = &(monotonicCounters[*countID]); (*tpm_counter_value)->valid = TRUE; /* mark it occupied */ } else { printf("TPM_Counters_GetNewHandle: Error, no space in monotonicCounters table\n"); rc = TPM_RESOURCES; } return rc; } /* TPM_Counters_GetNextCount() searches the monotonicCounters for the maximum count, and returns nextCount equal to the incremented maximum count. The counter does not have to be valid (created). It can be invalid (released). */ void TPM_Counters_GetNextCount(TPM_ACTUAL_COUNT *nextCount, TPM_COUNTER_VALUE *monotonicCounters) { TPM_COUNT_ID countID; TPM_ACTUAL_COUNT maxCount = 0; printf(" TPM_Counters_GetNextCount:\n"); for (countID = 0 ; countID < TPM_MIN_COUNTERS ; countID++) { if (monotonicCounters[countID].counter > maxCount) { maxCount = monotonicCounters[countID].counter; } } *nextCount = maxCount + 1; printf(" TPM_Counters_GetNextCount: Next count %u\n", *nextCount); return; } /* TPM_Counters_IsValidId() verifies that countID is in range and a created counter */ TPM_RESULT TPM_Counters_IsValidId(TPM_COUNTER_VALUE *monotonicCounters, TPM_COUNT_ID countID) { TPM_RESULT rc = 0; printf(" TPM_Counters_IsValidId: countID %u\n", countID); /* range check */ if (rc == 0) { if (countID >= TPM_MIN_COUNTERS) { printf("TPM_Counters_IsValidId: Error countID %u out of range\n", countID); rc = TPM_BAD_COUNTER ; } } /* validity (creation) check */ if (rc == 0) { if (!(monotonicCounters[countID].valid)) { printf("TPM_Counters_IsValidId: Error countID %u invalid\n", countID); rc = TPM_BAD_COUNTER ; } } return rc; } /* TPM_Counters_GetCounterValue() gets the TPM_COUNTER_VALUE associated with the countID. */ TPM_RESULT TPM_Counters_GetCounterValue(TPM_COUNTER_VALUE **tpm_counter_value, TPM_COUNTER_VALUE *monotonicCounters, TPM_COUNT_ID countID) { TPM_RESULT rc = 0; printf(" TPM_Counters_GetCounterValue: countID %u\n", countID); /* valid counter check */ if (rc == 0) { rc = TPM_Counters_IsValidId(monotonicCounters, countID); } if (rc == 0) { *tpm_counter_value = &(monotonicCounters[countID]); } return rc; } /* TPM_Counters_Release() iterates through all monotonicCounter's, and releases those that are created. The resource is set invalid, and the authorization data and digest are cleared. a. This includes invalidating all currently allocated counters. The result will be no currently allocated counters and the new owner will need to allocate counters. The actual count value will continue to increase. */ TPM_RESULT TPM_Counters_Release(TPM_COUNTER_VALUE *monotonicCounters) { TPM_RESULT rc = 0; TPM_COUNT_ID i; printf(" TPM_Counters_Release:\n"); for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { if (monotonicCounters[i].valid) { /* the actual count value does not reset to zero */ printf(" TPM_Counters_Release: Releasing %u\n", i); TPM_Secret_Init(monotonicCounters[i].authData); TPM_Digest_Init(monotonicCounters[i].digest); monotonicCounters[i].valid = FALSE; } } return rc; } /* TPM_Counters_GetActiveCounter() gets the active counter based on the value in TPM_STCLEAR_DATA -> countID */ void TPM_Counters_GetActiveCounter(TPM_COUNT_ID *activeCounter, TPM_COUNT_ID countID) { if (countID < TPM_MIN_COUNTERS) { *activeCounter = countID; } else { *activeCounter = TPM_COUNT_ID_NULL; } } /* TPM_COUNTER_VALUE */ /* TPM_CounterValue_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_CounterValue_Init(TPM_COUNTER_VALUE *tpm_counter_value) { printf(" TPM_CounterValue_Init:\n"); memset(tpm_counter_value->label, 0, TPM_COUNTER_LABEL_SIZE); tpm_counter_value->counter = 0; TPM_Secret_Init(tpm_counter_value->authData); tpm_counter_value->valid = FALSE; return; } /* TPM_CounterValue_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes */ TPM_RESULT TPM_CounterValue_Load(TPM_COUNTER_VALUE *tpm_counter_value, /* result */ unsigned char **stream, /* pointer to next parameter */ uint32_t *stream_size) /* stream size left */ { TPM_RESULT rc = 0; printf(" TPM_CounterValue_Load:\n"); /* check tag */ if (rc == 0) { rc = TPM_CheckTag(TPM_TAG_COUNTER_VALUE, stream, stream_size); } /* load label */ if (rc == 0) { rc = TPM_Loadn(tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE, stream, stream_size); } /* load counter */ if (rc == 0) { rc = TPM_Load32(&(tpm_counter_value->counter), stream, stream_size); } /* load authData */ if (rc == 0) { rc = TPM_Secret_Load(tpm_counter_value->authData, stream, stream_size); } /* load valid */ if (rc == 0) { rc = TPM_LoadBool(&(tpm_counter_value->valid), stream, stream_size); } return rc; } /* TPM_CounterValue_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes It is typically used to store the structure in the permanent data file. */ TPM_RESULT TPM_CounterValue_Store(TPM_STORE_BUFFER *sbuffer, const TPM_COUNTER_VALUE *tpm_counter_value) { TPM_RESULT rc = 0; printf(" TPM_CounterValue_Store:\n"); /* store tag, label, counter */ if (rc == 0) { rc = TPM_CounterValue_StorePublic(sbuffer, tpm_counter_value); } /* store authData */ if (rc == 0) { rc = TPM_Secret_Store(sbuffer, tpm_counter_value->authData); } /* store valid */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, &(tpm_counter_value->valid), sizeof(TPM_BOOL)); } return rc; } /* TPM_CounterValue_StorePublic() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes This version only stores the public, externally visible fields: tag, label, counter. It is typically used to return outgoing parameters. */ TPM_RESULT TPM_CounterValue_StorePublic(TPM_STORE_BUFFER *sbuffer, const TPM_COUNTER_VALUE *tpm_counter_value) { TPM_RESULT rc = 0; printf(" TPM_CounterValue_StorePublic:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_COUNTER_VALUE); } /* store label */ if (rc == 0) { rc = TPM_Sbuffer_Append(sbuffer, tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); } /* store counter */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_counter_value->counter); } return rc; } /* TPM_CounterValue_CopyPublic() copies the public, externally visible fields: tag, label, counter. */ void TPM_CounterValue_CopyPublic(TPM_COUNTER_VALUE *dst_tpm_counter_value, TPM_COUNTER_VALUE *src_tpm_counter_value) { memcpy(dst_tpm_counter_value->label, src_tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); dst_tpm_counter_value->counter = src_tpm_counter_value->counter; return; } /* TPM_CounterValue_Set() Sets the label, counter, and authData members from input parameters, and sets the digest from members. */ TPM_RESULT TPM_CounterValue_Set(TPM_COUNTER_VALUE *tpm_counter_value, TPM_COUNT_ID countID, BYTE *label, TPM_ACTUAL_COUNT counter, TPM_SECRET authData) { TPM_RESULT rc = 0; printf(" TPM_CounterValue_Set:\n"); tpm_counter_value->counter = counter; memcpy(tpm_counter_value->label, label, TPM_COUNTER_LABEL_SIZE); TPM_Secret_Copy(tpm_counter_value->authData, authData); /* create a hopefully unique digest of the object for the OSAP setup. The cast is OK here since the actual value of the digest is never verified. */ rc = TPM_SHA1(tpm_counter_value->digest, sizeof(TPM_COUNT_ID), (unsigned char *)&countID, TPM_COUNTER_LABEL_SIZE, label, TPM_SECRET_SIZE, authData, 0, NULL); return rc; } /* TPM_CounterValue_Release() releases a counter. The resource is set invalid, and the authorization data and digest are cleared. */ TPM_RESULT TPM_CounterValue_Release(TPM_COUNTER_VALUE *tpm_counter_value, TPM_COUNT_ID countID) { TPM_RESULT rc = 0; printf(" TPM_CounterValue_Release: countID %u\n", countID); /* sanity check */ if (rc == 0) { if (!tpm_counter_value->valid) { printf("TPM_CounterValue_Release: Error (fatal), countID %u not valid\n", countID); rc = TPM_FAIL; /* should never occur */ } } if (rc == 0) { TPM_Secret_Init(tpm_counter_value->authData); TPM_Digest_Init(tpm_counter_value->digest); tpm_counter_value->valid = FALSE; } return rc; } /* Processing Functions */ /* 25.1 TPM_CreateCounter rev 98 This command creates the counter but does not select the counter. Counter creation assigns an AuthData value to the counter and sets the counters original start value. The original start value is the current internal base value plus one. Setting the new counter to the internal base avoids attacks on the system that are attempting to use old counter values. This command creates a new monotonic counter. The TPM MUST support a minimum of 4 concurrent counters. */ TPM_RESULT TPM_Process_CreateCounter(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_ENCAUTH encAuth; /* The encrypted auth data for the new counter */ BYTE label[TPM_COUNTER_LABEL_SIZE]; /* Label to associate with counter */ 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; /* Ignored */ TPM_AUTHDATA ownerAuth; /* Authorization 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 = FALSE; /* audit the ordinal */ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey = NULL; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_SECRET a1Auth; TPM_ACTUAL_COUNT nextCount; TPM_BOOL writeAllNV= FALSE; /* flag to write back NV */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_COUNT_ID countID = 0; /* The handle for the counter */ TPM_COUNTER_VALUE *counterValue = NULL; /* The starting counter value */ printf("TPM_Process_CreateCounter: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get authData */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); } /* get label */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Loadn(label, TPM_COUNTER_LABEL_SIZE, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { TPM_PrintFour("TPM_Process_CreateCounter: 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_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_CreateCounter: 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. Using the authHandle field, validate the owner's AuthData to execute the command and all of the incoming parameters. The authorization session MUST be OSAP or DSAP. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_OSAP, TPM_ET_OWNER, ordinal, NULL, NULL, tpm_state->tpm_permanent_data.ownerAuth); } if (returnCode == TPM_SUCCESS) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, ownerAuth); /* Authorization digest for input */ } /* 2. Ignore continueAuthSession on input and set continueAuthSession to FALSE on output */ if (returnCode == TPM_SUCCESS) { continueAuthSession = FALSE; } /* 3. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthSessionData_Decrypt(a1Auth, NULL, encAuth, auth_session_data, NULL, NULL, FALSE); /* even and odd */ } /* 4. Validate that there is sufficient internal space in the TPM to create a new counter. If there is insufficient space the command returns an error. */ /* a. The TPM MUST provide storage for a1, TPM_COUNTER_VALUE, countID, and any other internal data the TPM needs to associate with the counter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Counters_GetNewHandle(&counterValue, /* structure */ &countID, /* index */ tpm_state->tpm_permanent_data.monotonicCounter); } if (returnCode == TPM_SUCCESS) { writeAllNV = TRUE; /* 5. Increment the max counter value */ TPM_Counters_GetNextCount(&nextCount, tpm_state->tpm_permanent_data.monotonicCounter); /* 6. Set the counter to the max counter value */ /* 7. Set the counter label to label */ returnCode = TPM_CounterValue_Set(counterValue, countID, label, nextCount, a1Auth); /* 8. Create a countID */ /* NOTE Done in TPM_Counters_GetNewHandle() */ } /* save the permanent data structure in NVRAM */ returnCode = TPM_PermanentAll_NVStore(tpm_state, writeAllNV, returnCode); /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_CreateCounter: 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 the countID */ returnCode = TPM_Sbuffer_Append32(response, countID); } if (returnCode == TPM_SUCCESS) { /* Return the TPM_COUNTER_VALUE publicly visible members */ returnCode = TPM_CounterValue_StorePublic(response, counterValue); /* 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, /* 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 */ return rcf; } /* 25.2 TPM_IncrementCounter rev 87 This authorized command increments the indicated counter by one. Once a counter has been incremented then all subsequent increments must be for the same handle until a successful TPM_Startup(ST_CLEAR) is executed. The order for checking validation of the command parameters when no counter is active, keeps an attacker from creating a denial-of-service attack. This function increments the counter by 1. The TPM MAY implement increment throttling to avoid burn problems */ TPM_RESULT TPM_Process_IncrementCounter(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_COUNT_ID countID; /* The handle of a valid counter */ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for counter 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 counterAuth; /* The authorization session digest that authorizes the use of countID. HMAC key: countID -> authData */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus; /* audit the ordinal */ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_COUNTER_VALUE *counterValue = NULL; /* The counter value */ printf("TPM_Process_IncrementCounter: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&countID, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_IncrementCounter: countID %u\n", countID); } /* 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, counterAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_IncrementCounter: 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 */ /* The first check is that either there is no active counter and the countID has been created or that the countID is the active counter */ if (returnCode == TPM_SUCCESS) { /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { /* a. Validate that countID is a valid counter, return TPM_BAD_COUNTER on mismatch */ returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, countID); } /* 2. else (TPM_STCLEAR_DATA -> countID is not NULL */ else { /* a. If TPM_STCLEAR_DATA -> countID does not equal countID */ if (tpm_state->tpm_stclear_data.countID != countID) { if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_ILLEGAL) { printf("TPM_Process_IncrementCounter: Error, counter has been released\n"); } else { printf("TPM_Process_IncrementCounter: Error, %u is already active\n", tpm_state->tpm_stclear_data.countID); } /* i. Return TPM_BAD_COUNTER */ returnCode = TPM_BAD_COUNTER; } } } /* b. Validate the command parameters using counterAuth */ /* Get the TPM_COUNTER_VALUE associated with the countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Counters_GetCounterValue(&counterValue, tpm_state->tpm_permanent_data.monotonicCounter, countID); } /* get the session data */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_COUNTER, ordinal, NULL, &(counterValue->authData), /* OIAP */ counterValue->digest); /* OSAP */ } /* Validate the authorization to use the key pointed to by keyHandle */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, counterAuth); /* Authorization digest for input */ } if (returnCode == TPM_SUCCESS) { /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { /* c. Set TPM_STCLEAR_DATA -> countID to countID */ tpm_state->tpm_stclear_data.countID = countID; printf("TPM_Process_IncrementCounter: Setting %u as active counter\n", countID); } } if (returnCode == TPM_SUCCESS) { /* 3. Increments the counter by 1 */ counterValue->counter++; /* in TPM_PERMANENT_DATA */ /* save the permanent data structure in NVRAM */ returnCode = TPM_PermanentAll_NVStore(tpm_state, TRUE, returnCode); } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_IncrementCounter: 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; /* 4. Return new count value in count */ returnCode = TPM_CounterValue_StorePublic(response, counterValue); /* 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 */ return rcf; } /* 25.3 TPM_ReadCounter rev 87 Reading the counter provides the caller with the current number in the sequence. This returns the current value for the counter indicated. The counter MAY be any valid counter. */ TPM_RESULT TPM_Process_ReadCounter(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_COUNT_ID countID; /* ID value of the counter */ /* 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_ReadCounter: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&countID, &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_ReadCounter: Error, command has %u extra bytes\n", paramSize); returnCode = TPM_BAD_PARAM_SIZE; } } /* Processing */ /* 1. Validate that countID points to a valid counter. Return TPM_BAD_COUNTER on error. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReadCounter: countID %u\n", countID); returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, countID); } /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_ReadCounter: 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 count (directly from TPM_PERMANENT_DATA) */ returnCode = TPM_CounterValue_StorePublic (response, &(tpm_state->tpm_permanent_data.monotonicCounter[countID])); /* 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; } /* 25.4 TPM_ReleaseCounter rev 87 This command releases a counter such that no reads or increments of the indicated counter will succeed. The TPM uses countID to locate a valid counter. */ TPM_RESULT TPM_Process_ReleaseCounter(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_COUNT_ID countID; /* ID value of the counter */ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for countID authorization */ TPM_NONCE nonceOdd; /* Nonce associated with countID */ TPM_BOOL continueAuthSession = TRUE; /* Ignored */ TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use of countID. HMAC key: countID -> authData */ /* processing parameters */ unsigned char * inParamStart; /* starting point of inParam's */ unsigned char * inParamEnd; /* ending point of inParam's */ TPM_DIGEST inParamDigest; TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_COUNTER_VALUE *counterValue; /* associated with countID */ TPM_SECRET savedAuth; /* saved copy for response */ TPM_BOOL writeAllNV = FALSE; /* flag to write back NV*/ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; printf("TPM_Process_ReleaseCounter: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&countID, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReleaseCounter: countID %u\n", countID); } /* 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_CheckRequestTag1(tag); } /* get the 'below the line' authorization parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthParams_Get(&authHandle, &authHandleValid, nonceOdd, &continueAuthSession, counterAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_ReleaseCounter: 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. Authenticate the command and the parameters using the AuthData pointed to by countID. Return TPM_AUTHFAIL on error */ /* Get the TPM_COUNTER_VALUE associated with the countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Counters_GetCounterValue(&counterValue, tpm_state->tpm_permanent_data.monotonicCounter, countID); } /* get the session data */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_COUNTER, ordinal, NULL, &(counterValue->authData), /* OIAP */ counterValue->digest); /* OSAP */ } if (returnCode == TPM_SUCCESS) { /* make a copy of the HMAC key for the response, since it gets invalidated */ TPM_Secret_Copy(savedAuth, *hmacKey); /* Validate the authorization to use the key pointed to by countID */ returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, counterAuth); /* Authorization digest for input */ } /* 3. The TPM invalidates sessions */ /* a. MUST invalidate all OSAP sessions associated with the counter */ /* b. MAY invalidate any other session */ /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ if (returnCode == TPM_SUCCESS) { TPM_AuthSessions_TerminateEntity(&continueAuthSession, authHandle, tpm_state->tpm_stclear_data.authSessions, TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ &(counterValue->digest)); /* entityDigest */ } /* 2. The TPM invalidates all internal information regarding the counter. This includes releasing countID such that any subsequent attempts to use countID will fail. */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReleaseCounter: Releasing counter %u\n", countID); returnCode = TPM_CounterValue_Release(counterValue, countID); } if (returnCode == TPM_SUCCESS) { writeAllNV= TRUE; /* 4. If TPM_STCLEAR_DATA -> countID equals countID, */ if (tpm_state->tpm_stclear_data.countID == countID ) { printf("TPM_Process_ReleaseCounter: Deactivating counter %u\n", countID); /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the NULL value) */ tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; } } /* save the permanent data structure in NVRAM */ returnCode = TPM_PermanentAll_NVStore(tpm_state, writeAllNV, returnCode); /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_ReleaseCounter: 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, savedAuth, /* saved countID 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, 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 */ return rcf; } /* 25.5 TPM_ReleaseCounterOwner rev 101 This command releases a counter such that no reads or increments of the indicated counter will succeed. This invalidates all information regarding a counter. */ TPM_RESULT TPM_Process_ReleaseCounterOwner(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 */ TPM_COUNT_ID countID; /* ID value of the counter */ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner authentication */ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA ownerAuth; /* The authorization session digest that authorizes the inputs. HMAC 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 = FALSE; /* audit the ordinal */ TPM_BOOL transportEncrypt = TRUE; /* wrapped in encrypted transport session */ TPM_BOOL authHandleValid = FALSE; TPM_SECRET *hmacKey = NULL; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_COUNTER_VALUE *counterValue; /* associated with countID */ TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; printf("TPM_Process_ReleaseCounterOwner: Ordinal Entry\n"); /* get inputs */ /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&countID, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReleaseCounterOwner: countID %u\n", countID); } /* 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_ReleaseCounterOwner: 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 that ownerAuth properly authorizes the command and parameters */ 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. The TPM uses countID to locate a valid counter. Return TPM_BAD_COUNTER if not found. */ /* Get the TPM_COUNTER_VALUE associated with the countID */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Counters_GetCounterValue(&counterValue, tpm_state->tpm_permanent_data.monotonicCounter, countID); } /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ if (returnCode == TPM_SUCCESS) { TPM_AuthSessions_TerminateEntity(&continueAuthSession, authHandle, tpm_state->tpm_stclear_data.authSessions, TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ &(counterValue->digest)); /* entityDigest */ } /* 3. The TPM invalidates all internal information regarding the counter. This includes releasing countID such that any subsequent attempts to use countID will fail. */ /* NOTE: This function can only return a TPM_FAIL error, so that the failure to store TPM_PERMANENT_DATA will already be reported as fatal. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CounterValue_Release(counterValue, countID); } /* 4. The TPM invalidates sessions */ /* a. MUST invalidate all OSAP sessions associated with the counter */ /* b. MAY invalidate any other session */ if (returnCode == TPM_SUCCESS) { writeAllNV = TRUE; /* 5. If TPM_STCLEAR_DATA -> countID equals countID, */ if (tpm_state->tpm_stclear_data.countID == countID ) { printf("TPM_Process_ReleaseCounterOwner: Deactivating counter %u\n", countID); /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the zero value) */ tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; } } /* save the permanent data structure in NVRAM */ returnCode = TPM_PermanentAll_NVStore(tpm_state, writeAllNV, returnCode); /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_ReleaseCounterOwner: 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, /* 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, 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 */ return rcf; }