summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm12/tpm_counter.c')
-rw-r--r--src/tpm12/tpm_counter.c1565
1 files changed, 1565 insertions, 0 deletions
diff --git a/src/tpm12/tpm_counter.c b/src/tpm12/tpm_counter.c
new file mode 100644
index 0000000..65a2db2
--- /dev/null
+++ b/src/tpm12/tpm_counter.c
@@ -0,0 +1,1565 @@
+/********************************************************************************/
+/* */
+/* 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 <stdio.h>
+#include <string.h>
+
+#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, &paramSize);
+ }
+ /* get label */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Loadn(label, TPM_COUNTER_LABEL_SIZE, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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;
+}