summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm12/tpm_auth.c')
-rw-r--r--src/tpm12/tpm_auth.c2301
1 files changed, 2301 insertions, 0 deletions
diff --git a/src/tpm12/tpm_auth.c b/src/tpm12/tpm_auth.c
new file mode 100644
index 0000000..70888d7
--- /dev/null
+++ b/src/tpm12/tpm_auth.c
@@ -0,0 +1,2301 @@
+/********************************************************************************/
+/* */
+/* Authorization */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: tpm_auth.c 4438 2011-02-13 23:03:56Z 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 <stdlib.h>
+
+#include "tpm_crypto.h"
+#include "tpm_cryptoh.h"
+#include "tpm_debug.h"
+#include "tpm_digest.h"
+#include "tpm_error.h"
+#include "tpm_init.h"
+#include "tpm_key.h"
+#include "tpm_memory.h"
+#include "tpm_nonce.h"
+#include "tpm_permanent.h"
+#include "tpm_process.h"
+#include "tpm_secret.h"
+#include "tpm_storage.h"
+#include "tpm_time.h"
+#include "tpm_transport.h"
+
+#include "tpm_auth.h"
+
+/* Dictionary attack mitigation:
+
+ TPM_Authdata_CheckState() - called at command entry
+ if past limit,
+ check authFailTime vs. current time
+ if command allowed
+ disableResetLock = FALSE
+
+ TPM_Authdata_Check() - called during the command to validate authorization data
+ TPM_Authdata_Fail() - called on failure
+ authFailCount++
+ if past limit,
+ authFailTime = current time
+
+ TPM_ResetLockValue
+ TPM_Authdata_CheckState()
+ disableResetLock = FALSE if no lockout
+ if disableResetLock, return error
+ if authorization failure
+ disableResetLock = TRUE
+ authFailCount = 0
+*/
+
+#if 0
+/* TPM_Authdata_Init() zeros the tpm_authdata
+
+*/
+
+void TPM_Authdata_Init(TPM_AUTHDATA tpm_authdata)
+{
+ printf(" TPM_Authdata_Init:\n");
+ memset(tpm_authdata, 0, TPM_AUTHDATA_SIZE);
+ return;
+}
+#endif
+
+/* TPM_Authdata_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_Authdata_Load(TPM_AUTHDATA tpm_authdata,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Authdata_Load:\n");
+
+ /* check stream_size */
+ if (rc == 0) {
+ if (*stream_size < TPM_AUTHDATA_SIZE) {
+ printf("TPM_Authdata_Load: Error, stream_size %u less than %u\n",
+ *stream_size, TPM_DIGEST_SIZE);
+ rc = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ if (rc == 0) {
+ memcpy(tpm_authdata, *stream, TPM_AUTHDATA_SIZE);
+ *stream += TPM_AUTHDATA_SIZE;
+ *stream_size -= TPM_AUTHDATA_SIZE;
+ }
+ return rc;
+}
+
+/* TPM_Authdata_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+
+ After use, call TPM_Sbuffer_Delete() to free memory
+*/
+
+TPM_RESULT TPM_Authdata_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_AUTHDATA tpm_authdata)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Authdata_Store:\n");
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, tpm_authdata, TPM_AUTHDATA_SIZE);
+ }
+ return rc;
+}
+
+/* TPM_AuthParams_Get() is common code to load a set of "below the double line" request parameters
+ from the input stream.
+ */
+
+TPM_RESULT TPM_AuthParams_Get(TPM_AUTHHANDLE *authHandle, /* The authorization handle used for
+ this command */
+ TPM_BOOL *authHandleValid,
+ TPM_NONCE nonceOdd, /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL *continueAuthSession, /* The continue use flag for the
+ authorization handle */
+ TPM_AUTHDATA authData, /* Authorization digest for input params. */
+ unsigned char **command, /* parameter stream */
+ uint32_t *paramSize) /* bytes left in command */
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_AuthParams_Get:\n");
+ /* get authHandle parameter */
+ if (rc == 0) {
+ rc = TPM_Load32(authHandle, command, paramSize);
+ }
+ /* get nonceOdd parameter */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(nonceOdd, command, paramSize);
+ }
+ /* get continueAuthSession parameter */
+ if (rc == 0) {
+ rc = TPM_LoadBool(continueAuthSession, command, paramSize);
+ }
+ /* get authData parameter */
+ if (rc == 0) {
+ rc = TPM_Authdata_Load(authData, command, paramSize);
+ }
+ if (rc == 0) {
+ *authHandleValid = TRUE; /* so handle can be terminated */
+ }
+ return rc;
+}
+
+
+/* TPM_SetAuthParams is common code to set a set of "below the double line" response parameters.
+ */
+
+TPM_RESULT TPM_AuthParams_Set(TPM_STORE_BUFFER *response,
+ TPM_SECRET hmacKey, /* HMAC key */
+ TPM_AUTH_SESSION_DATA *auth_session_data, /* session data for
+ authHandle */
+ TPM_DIGEST outParamDigest,
+ TPM_NONCE nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ TPM_BOOL continueAuthSession) /* session continue use flag */
+{
+ TPM_RESULT rc = 0;
+ TPM_AUTHDATA resAuth; /* The authorization digest for the returned parameters */
+
+ printf(" TPM_AuthParams_Set:\n");
+ /* generate new nonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Generate(auth_session_data->nonceEven);
+ }
+ /* append nonceEven */
+ if (rc == 0) {
+ rc = TPM_Nonce_Store(response, auth_session_data->nonceEven);
+ }
+ /* append continueAuthSession */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(response, &continueAuthSession, sizeof(TPM_BOOL));
+ }
+ /* Calculate resAuth using the hmac key */
+ if (rc == 0) {
+ rc = TPM_Authdata_Generate(resAuth, /* result */
+ hmacKey, /* HMAC key */
+ outParamDigest, /* params */
+ auth_session_data->nonceEven,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* append resAuth */
+ if (rc == 0) {
+ rc = TPM_Authdata_Store(response, resAuth);
+ }
+ return rc;
+}
+
+TPM_RESULT TPM_Authdata_Generate(TPM_AUTHDATA resAuth, /* result */
+ TPM_SECRET usageAuth, /* HMAC key */
+ TPM_DIGEST outParamDigest, /* digest of outputs above double
+ line */
+ TPM_NONCE nonceEven,
+ TPM_NONCE nonceOdd,
+ TPM_BOOL continueSession)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Authdata_Generate:\n");
+ if (rc == 0) {
+ TPM_PrintFour(" TPM_Authdata_Generate: outParamDigest", outParamDigest);
+ TPM_PrintFour(" TPM_Authdata_Generate: usageAuth (key)", usageAuth);
+ TPM_PrintFour(" TPM_Authdata_Generate: nonceEven", nonceEven);
+ TPM_PrintFour(" TPM_Authdata_Generate: nonceOdd", nonceOdd);
+ printf (" TPM_Authdata_Generate: continueSession %02x\n", continueSession);
+ rc = TPM_HMAC_Generate(resAuth,
+ usageAuth, /* key */
+ TPM_DIGEST_SIZE, outParamDigest, /* response digest */
+ TPM_NONCE_SIZE, nonceEven, /* 2H */
+ TPM_NONCE_SIZE, nonceOdd, /* 3H */
+ sizeof(TPM_BOOL), &continueSession, /* 4H */
+ 0, NULL);
+ TPM_PrintFour(" TPM_Authdata_Generate: resAuth", resAuth);
+ }
+ return rc;
+}
+
+/* TPM_Authdata_Check() checks the authorization of a command.
+
+ Handles the protection against dictionary attacks.
+
+ Returns TPM_AUTHFAIL if the TPM_AUTHDATA does not match.
+*/
+
+TPM_RESULT TPM_Authdata_Check(tpm_state_t *tpm_state,
+ TPM_SECRET hmacKey, /* HMAC key */
+ TPM_DIGEST inParamDigest, /* digest of inputs above line */
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data, /* auth session */
+ TPM_NONCE nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ TPM_BOOL continueSession,
+ TPM_AUTHDATA usageAuth) /* Authorization digest for input */
+{
+ TPM_RESULT rc = 0;
+ TPM_BOOL valid;
+
+ printf(" TPM_Authdata_Check:\n");
+ if (rc == 0) {
+ TPM_PrintFour(" TPM_Authdata_Check: inParamDigest", inParamDigest);
+ TPM_PrintFour(" TPM_Authdata_Check: usageAuth (key)", hmacKey);
+ TPM_PrintFour(" TPM_Authdata_Check: nonceEven", tpm_auth_session_data->nonceEven);
+ TPM_PrintFour(" TPM_Authdata_Check: nonceOdd", nonceOdd);
+ printf (" TPM_Authdata_Check: continueSession %02x\n", continueSession);
+ /* HMAC the inParamDigest, authLastNonceEven, nonceOdd, continue */
+ /* authLastNonceEven is retrieved from internal authorization session storage */
+ rc = TPM_HMAC_Check(&valid,
+ usageAuth, /* expected, from command */
+ hmacKey, /* key */
+ sizeof(TPM_DIGEST), inParamDigest, /* command digest */
+ sizeof(TPM_NONCE), tpm_auth_session_data->nonceEven, /* 2H */
+ sizeof(TPM_NONCE), nonceOdd, /* 3H */
+ sizeof(TPM_BOOL), &continueSession, /* 4H */
+ 0, NULL);
+ }
+ if (rc == 0) {
+ if (!valid) {
+ printf("TPM_Authdata_Check: Error, authorization failed\n");
+ /* record the authorization failure */
+ rc = TPM_Authdata_Fail(tpm_state);
+ /* TPM_Authdata_Fail() fatal TPM_FAIL error takes precedence, else TPM_AUTHFAIL */
+ if (rc == 0) {
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ }
+ return rc;
+}
+
+/* TPM_Auth2data_Check() is a wrapper around TPM_Authdata_Check() that returns TPM_AUTH2FAIL
+ in place of TPM_AUTHFAIL.
+*/
+
+TPM_RESULT TPM_Auth2data_Check(tpm_state_t *tpm_state,
+ TPM_SECRET hmacKey, /* HMAC key */
+ TPM_DIGEST inParamDigest, /* digest of inputs above line */
+ TPM_AUTH_SESSION_DATA *tpm_auth_session_data, /* auth session */
+ TPM_NONCE nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ TPM_BOOL continueSession,
+ TPM_AUTHDATA usageAuth) /* Authorization digest for input */
+{
+ TPM_RESULT rc = 0;
+
+ rc = TPM_Authdata_Check(tpm_state,
+ hmacKey,
+ inParamDigest,
+ tpm_auth_session_data,
+ nonceOdd,
+ continueSession,
+ usageAuth);
+ if (rc == TPM_AUTHFAIL) {
+ rc = TPM_AUTH2FAIL;
+ }
+ return rc;
+}
+
+/* TPM_Authdata_Fail() processes an authorization failure event, to mitigate dictionary attacks.
+
+ Returns TPM_FAIL on error, so that the caller can shut down the TPM
+*/
+
+TPM_RESULT TPM_Authdata_Fail(tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ uint32_t tv_usec; /* dummy, discard usec */
+
+ if (rc == 0) {
+ /* Each failure increments the counter. No need to check for overflow. Unless
+ TPM_LOCKOUT_THRESHOLD is absurdly large, the left shift overflows first. */
+ tpm_state->tpm_stclear_data.authFailCount++;
+ printf(" TPM_Authdata_Fail: New authFailCount %u\n",
+ tpm_state->tpm_stclear_data.authFailCount);
+ /* Test if past the failure threshold. Each time authorization fails, this test is made.
+ Once in dictionary attack mitigation, there will be no authdata check until the
+ mitigation period is exceeded. After that, if there is another failure, the fail count
+ increases and mitigation begins again.
+
+ Note that a successful authorization does NOT reset authFailCount, as this would allow a
+ dictionary attack by an attacker that knew ANY good authorization value. The count is
+ only reset by the owner using TPM_ResetLockValue.
+ */
+ if (tpm_state->tpm_stclear_data.authFailCount > TPM_LOCKOUT_THRESHOLD) {
+ /* the current authorization failure time is the start time */
+ rc = TPM_GetTimeOfDay(&(tpm_state->tpm_stclear_data.authFailTime), &tv_usec);
+ printf(" TPM_Authdata_Fail: Past limit, authFailTime %u\n",
+ tpm_state->tpm_stclear_data.authFailTime);
+ }
+ }
+ return rc;
+}
+
+/* TPM_Authdata_GetState() gets the boolean dictionary attack mitigation state.
+
+ */
+
+TPM_RESULT TPM_Authdata_GetState(TPM_DA_STATE *state,
+ uint32_t *timeLeft,
+ tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ uint32_t currentTime; /* in seconds */
+ uint32_t tv_usec; /* dummy, discarded */
+ uint32_t threshold_diff; /* in failure counts */
+ uint32_t waitTime; /* in seconds, timeout based on threshold_diff */
+ uint32_t timeDiff; /* in seconds, how far along is timeout */
+
+ printf(" TPM_Authdata_GetState:\n");
+ *state = TPM_DA_STATE_INACTIVE; /* default value */
+
+ /* if there is an attack in progress */
+ if (tpm_state->tpm_stclear_data.authFailCount > TPM_LOCKOUT_THRESHOLD) {
+ printf(" TPM_Authdata_GetState: In timeout, authFailCount %u threshold %u\n",
+ tpm_state->tpm_stclear_data.authFailCount, TPM_LOCKOUT_THRESHOLD);
+ /* get the current time */
+ if (rc == 0) {
+ /* throw away usec. This means that the time difference could be 1 sec off. But the
+ lockout mechanism is somewhat arbitrary anyway */
+ rc = TPM_GetTimeOfDay(&currentTime, &tv_usec);
+ }
+ /* calculate how much time to wait */
+ if (rc == 0) {
+ printf(" TPM_Authdata_GetState: currentTime %u authFailTime %u\n",
+ currentTime, tpm_state->tpm_stclear_data.authFailTime);
+ /* how many failures over the threshold. The -1 makes threshold_diff 0 based, so the
+ first waitTime is 1 sec. */
+ threshold_diff = tpm_state->tpm_stclear_data.authFailCount - TPM_LOCKOUT_THRESHOLD - 1;
+ /* Wait time depends on how far over threshold, wait 1 sec and double each time. Ignore
+ shift overflow, since the previous timeout 0x80000000 sec is 68 years. */
+ waitTime = 0x01 << threshold_diff;
+ /* how far along is timeout. */
+ if (currentTime >= tpm_state->tpm_stclear_data.authFailTime) {
+ timeDiff = currentTime - tpm_state->tpm_stclear_data.authFailTime;
+ }
+ /* handle unlikely currentTime wrap around */
+ else {
+ timeDiff = ((0xffffffff - tpm_state->tpm_stclear_data.authFailTime) +
+ currentTime) + 1;
+ }
+ /* if not past the timeout, return an error */
+ printf(" TPM_Authdata_GetState: waitTime %u timeDiff %u\n",
+ waitTime, timeDiff);
+ if (waitTime > timeDiff) {
+ printf("TPM_Authdata_GetState: Error, timeout not complete\n");
+ *state = TPM_DA_STATE_ACTIVE;
+ *timeLeft = waitTime - timeDiff;
+ }
+ }
+ }
+ return rc;
+}
+
+/* TPM_Authdata_CheckState() checks the dictionary attack mitigation state.
+
+ This function is typically called at the beginning of each command.
+
+ If an attack is in progress, and the lockout timeout has not expired, an error is returned.
+*/
+
+TPM_RESULT TPM_Authdata_CheckState(tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ TPM_DA_STATE state;
+ uint32_t timeLeft;
+
+ printf(" TPM_Authdata_CheckState:\n");
+ /* Get the dictionary attack mitigation state */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&state, &timeLeft, tpm_state);
+ }
+ /* If not during the timeout period, allow the TPM_ResetLockValue ordinal */
+ if (rc == 0) {
+ if (state == TPM_DA_STATE_INACTIVE) {
+ tpm_state->tpm_stclear_data.disableResetLock = FALSE;
+ }
+ else { /* TPM_DA_STATE_ACTIVE */
+ rc = TPM_DEFEND_LOCK_RUNNING;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_CHANGEAUTH_VALIDATE
+*/
+
+/* TPM_ChangeauthValidate_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_ChangeauthValidate_Init(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ printf(" TPM_ChangeauthValidate_Init:\n");
+ TPM_Secret_Init(tpm_changeauth_validate->newAuthSecret);
+ TPM_Nonce_Init(tpm_changeauth_validate->n1);
+ return;
+}
+
+/* TPM_ChangeauthValidate_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_ChangeauthValidate_Init()
+ After use, call TPM_ChangeauthValidate_Delete() to free memory
+*/
+
+TPM_RESULT TPM_ChangeauthValidate_Load(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ChangeauthValidate_Load:\n");
+ /* load newAuthSecret */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_changeauth_validate->newAuthSecret, stream, stream_size);
+ }
+ /* load n1 */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_changeauth_validate->n1, stream, stream_size);
+ }
+ return rc;
+}
+
+#if 0
+/* TPM_ChangeauthValidate_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_ChangeauthValidate_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ChangeauthValidate_Store:\n");
+ /* store newAuthSecret */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->newAuthSecret);
+ }
+ /* store n1 */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->n1);
+ }
+ return rc;
+}
+#endif
+
+/* TPM_ChangeauthValidate_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_ChangeauthValidate_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_ChangeauthValidate_Delete(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ printf(" TPM_ChangeauthValidate_Delete:\n");
+ if (tpm_changeauth_validate != NULL) {
+ TPM_ChangeauthValidate_Init(tpm_changeauth_validate);
+ }
+ return;
+}
+
+/*
+ TPM_DA_INFO
+*/
+
+/* TPM_DaInfo_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DaInfo_Init(TPM_DA_INFO *tpm_da_info)
+{
+ printf(" TPM_DaInfo_Init:\n");
+/* tpm_da_info->tag = TPM_TAG_DA_INFO; */
+ tpm_da_info->state = TPM_DA_STATE_INACTIVE;
+ tpm_da_info->currentCount = 0;
+ tpm_da_info->thresholdCount = TPM_LOCKOUT_THRESHOLD;
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ tpm_da_info->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE;
+ tpm_da_info->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT;
+ tpm_da_info->actionDependValue = 0;
+ TPM_SizedBuffer_Init(&tpm_da_info->vendorData);
+ return;
+}
+
+/* TPM_DaInfo_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfo_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DA_INFO *tpm_da_info)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfo_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO);
+ }
+ /* store state */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info->state), sizeof(TPM_DA_STATE));
+ }
+ /* store currentCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->currentCount);
+ }
+ /* store thresholdCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->thresholdCount);
+ }
+ /* store actionAtThreshold */
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ /* store TPM_DA_ACTION_TYPE tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE);
+ }
+ /* store TPM_DA_ACTION_TYPE actions */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionAtThreshold.actions);
+ }
+ /* store actionDependValue */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionDependValue);
+ }
+ /* store vendorData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info->vendorData));
+ }
+ return rc;
+}
+
+/* TPM_DaInfo_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DaInfo_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DaInfo_Delete(TPM_DA_INFO *tpm_da_info)
+{
+ printf(" TPM_DaInfo_Delete:\n");
+ if (tpm_da_info != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_da_info->vendorData));
+ TPM_DaInfo_Init(tpm_da_info);
+ }
+ return;
+}
+
+/* TPM_DaInfoLimited_Set()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfo_Set(TPM_DA_INFO *tpm_da_info,
+ tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfo_Set:\n");
+ /* state: Dynamic. The actual state of the dictionary attack mitigation logic. */
+ /* actionDependValue: Dynamic. Action being taken when the dictionary attack mitigation logic
+ is active. E.g., when actionAtThreshold is TPM_DA_ACTION_TIMEOUT, this is the lockout time
+ remaining in seconds. */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&(tpm_da_info->state),
+ &(tpm_da_info->actionDependValue),
+ tpm_state);
+ }
+ /* Dynamic. The actual count of the authorization failure counter for the selected entity
+ type */
+ if (rc == 0) {
+ if (tpm_state->tpm_stclear_data.authFailCount <= 0xffff) {
+ tpm_da_info->currentCount = tpm_state->tpm_stclear_data.authFailCount;
+ }
+ /* with the doubling, this should never overflow. So overflow indicates a serious error */
+ else {
+ printf("TPM_DaInfo_Set: Error (fatal), authFailCount overflow %08x\n",
+ tpm_state->tpm_stclear_data.authFailCount);
+ rc = TPM_FAIL;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_DA_INFO_LIMITED
+*/
+
+/* TPM_DaInfoLimited_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DaInfoLimited_Init(TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ printf(" TPM_DaInfoLimited_Init:\n");
+/* tpm_da_info_limited->tag = TPM_TAG_DA_INFO_LIMITED; */
+ tpm_da_info_limited->state = TPM_DA_STATE_INACTIVE;
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ tpm_da_info_limited->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE;
+ tpm_da_info_limited->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT;
+ TPM_SizedBuffer_Init(&tpm_da_info_limited->vendorData);
+ return;
+}
+
+/* TPM_DaInfoLimited_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfoLimited_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfoLimited_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO_LIMITED);
+ }
+ /* store state */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info_limited->state), sizeof (TPM_DA_STATE));
+ }
+ /* store actionAtThreshold */
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ /* store TPM_DA_ACTION_TYPE tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE);
+ }
+ /* store TPM_DA_ACTION_TYPE actions */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info_limited->actionAtThreshold.actions);
+ }
+ /* store vendorData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info_limited->vendorData));
+ }
+ return rc;
+}
+
+/* TPM_DaInfoLimited_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DaInfoLimited_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DaInfoLimited_Delete(TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ printf(" TPM_DaInfoLimited_Delete:\n");
+ if (tpm_da_info_limited != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_da_info_limited->vendorData));
+ TPM_DaInfoLimited_Init(tpm_da_info_limited);
+ }
+ return;
+}
+
+/* TPM_DaInfoLimited_Set()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfoLimited_Set(TPM_DA_INFO_LIMITED *tpm_da_info_limited,
+ tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ uint32_t timeLeft;
+
+ printf(" TPM_DaInfoLimited_Set:\n");
+ /* Dynamic. The actual state of the dictionary attack mitigation logic. */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&(tpm_da_info_limited->state), &timeLeft, tpm_state);
+ }
+ return rc;
+}
+
+/*
+ Processing Functions
+*/
+
+
+/* 17.1 TPM_ChangeAuth rev 107
+
+ The TPM_ChangeAuth command allows the owner of an entity to change the authorization data for the
+ entity.
+
+ This command cannot invalidate the old entity. Therefore, the authorization change is only
+ effective if the application can guarantee that the old entity can be securely destroyed. If not,
+ two valid entities will exist, one with the old and one with the new authorization secret.
+
+ If this command is delegated, the delegated party can expand its key use privileges. That party
+ can create a copy of the key with known authorization, and it can then use the key without any
+ ordinal restrictions.
+
+ TPM_ChangeAuth requires the encryption of one parameter ("NewAuth"). For the sake of uniformity
+ with other commands that require the encryption of more than one parameter, the string used for
+ XOR encryption is generated by concatenating the evenNonce (created during the OSAP session) with
+ the session shared secret and then hashing the result.
+
+ The parameter list to this command must always include two authorization sessions, regardless of
+ the state of authDataUsage for the respective keys.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuth(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE parentHandle; /* Handle of the parent key to the entity. */
+ TPM_PROTOCOL_ID protocolID = 0; /* The protocol in use. */
+ TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */
+
+ TPM_AUTHHANDLE parentAuthHandle; /* The authorization handle used for the parent
+ key. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ parentAuthHandle */
+ TPM_BOOL continueAuthSession; /* Ignored, parentAuthHandle is always terminated. */
+ TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and
+ parentHandle. HMAC key: parentKey.usageAuth. */
+
+ TPM_AUTHHANDLE entityAuthHandle; /* The authorization handle used for the encrypted
+ entity. The session type MUST be OIAP */
+ TPM_NONCE entitynonceOdd; /* Nonce generated by system associated with
+ entityAuthHandle */
+ TPM_BOOL continueEntitySession; /* Ignored, entityAuthHandle is always terminated. */
+ TPM_AUTHDATA entityAuth; /* The authorization digest for the inputs and encrypted
+ entity. HMAC key: entity.usageAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL parentAuthHandleValid = FALSE;
+ TPM_BOOL entityAuthHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *parent_auth_session_data = NULL; /* session data for
+ parentAuthHandle */
+ TPM_AUTH_SESSION_DATA *entity_auth_session_data = NULL; /* session data for
+ entityAuthHandle */
+ TPM_KEY *parentKey = NULL;
+ TPM_SECRET *parentHmacKey;
+ TPM_SECRET *entityHmacKey;
+ TPM_SECRET saveKey; /* copy of entity HMAC key for response */
+ TPM_BOOL parentPCRStatus;
+ TPM_AUTHDATA decryptAuth;
+ unsigned char *b1DecryptData;
+ uint32_t b1DecryptDataLength = 0; /* actual valid data */
+ unsigned char *stream; /* for deserializing decrypted encData */
+ uint32_t stream_size;
+ TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */
+ TPM_SEALED_DATA sealEntity; /* entity structure when it's a TPM_ET_DATA */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */
+
+ printf("TPM_Process_ChangeAuth: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&encData); /* freed @1 */
+ TPM_SizedBuffer_Init(&outData); /* freed @2 */
+ b1DecryptData = NULL; /* freed @3 */
+ TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */
+ TPM_SealedData_Init(&sealEntity); /* freed @5 */
+ /*
+ get inputs
+ */
+ /* get parentHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&parentHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get protocolID parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: parentHandle %08x\n", parentHandle);
+ returnCode = TPM_Load16(&protocolID, &command, &paramSize);
+ }
+ /* get newAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: protocolID %04hx\n", protocolID);
+ returnCode = TPM_Authdata_Load(newAuth, &command, &paramSize);
+ }
+ /* get entityType parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get encData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: encDataSize %u\n", encData.size);
+ }
+ /* 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_CheckRequestTag2(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&parentAuthHandle,
+ &parentAuthHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ parentAuth,
+ &command, &paramSize);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: parentAuthHandle %08x\n", parentAuthHandle);
+ returnCode = TPM_AuthParams_Get(&entityAuthHandle,
+ &entityAuthHandleValid,
+ entitynonceOdd,
+ &continueEntitySession,
+ entityAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: entityAuthHandle %08x\n", entityAuthHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuth: 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) {
+ parentAuthHandleValid = FALSE;
+ entityAuthHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* Description
+ 1. The parentAuthHandle session type MUST be TPM_PID_OSAP.
+ 2. In this capability, the SRK cannot be accessed as entityType TPM_ET_KEY, since the SRK is
+ not wrapped by a parent key.
+ */
+ /* 1. Verify that entityType is one of TPM_ET_DATA, TPM_ET_KEY and return the error
+ TPM_WRONG_ENTITYTYPE if not. */
+ if (returnCode == TPM_SUCCESS) {
+ if ((entityType != TPM_ET_DATA) &&
+ (entityType != TPM_ET_KEY)) {
+ printf("TPM_Process_ChangeAuth: Error, bad entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* 2. Verify that parentAuthHandle session type is TPM_PID_OSAP return TPM_BAD_MODE on error */
+ /* get the key corresponding to the keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus,
+ tpm_state, parentHandle,
+ FALSE, /* not r/o, using to authenticate */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ /* get the OSAP session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&parent_auth_session_data,
+ &parentHmacKey,
+ tpm_state,
+ parentAuthHandle,
+ TPM_PID_OSAP,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ parentKey,
+ NULL, /* OIAP */
+ parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/
+ }
+ /* 3. Verify that entityAuthHandle session type is TPM_PID_OIAP return TPM_BAD_MODE on error */
+ /* keyEntity and sealEntity are not valid yet, so pass in NULL and ignore the returned
+ entityHmacKey */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&entity_auth_session_data,
+ &entityHmacKey,
+ tpm_state,
+ entityAuthHandle,
+ TPM_PID_OIAP,
+ 0, /* OSAP entity type */
+ ordinal,
+ NULL,
+ NULL,
+ NULL);
+ }
+ /* 4.If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */
+ if (returnCode == TPM_SUCCESS) {
+ if (protocolID != TPM_PID_ADCP) {
+ printf("TPM_Process_ChangeAuth: Error, bad protocolID\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 5. The encData field MUST be the encData field from either the TPM_STORED_DATA or TPM_KEY
+ structures. */
+ /* NOTE Seems the same as Action 1. */
+ /* 6. Create decryptAuth by decrypting newAuth according to the ADIP indicated by
+ parentHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(decryptAuth,
+ NULL,
+ newAuth,
+ parent_auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* odd and even */
+ }
+ /* 7. The TPM MUST validate the command using the authorization data in the parentAuth parameter
+ */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *parentHmacKey, /* HMAC key */
+ inParamDigest,
+ parent_auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ parentAuth); /* Authorization digest for input */
+ }
+ /* 8. Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return
+ TPM_INVALID_KEYUSAGE */
+ if (returnCode == TPM_SUCCESS) {
+ if (parentKey->keyUsage != TPM_KEY_STORAGE) {
+ printf("TPM_Process_ChangeAuth: Error, keyUsage %04hx is invalid\n",
+ parentKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 9. After parameter validation the TPM creates b1 by decrypting encData using the key pointed
+ to by parentHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&b1DecryptData, /* decrypted data */
+ &b1DecryptDataLength, /* actual size of
+ decrypted data */
+ encData.buffer,/* encrypted data */
+ encData.size, /* encrypted data size */
+ parentKey);
+ }
+ if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_KEY)) {
+ printf("TPM_Process_ChangeAuth: entityType is TPM_ET_KEY\n");
+ /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or
+ a TPM_SEALED_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ stream = b1DecryptData;
+ stream_size = b1DecryptDataLength;
+ returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE,
+ &stream, &stream_size,
+ NULL, /* TPM_KEY_PARMS */
+ NULL); /* TPM_SIZED_BUFFER pubKey */
+ }
+ /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */
+ /* NOTE: Done by TPM_StoreAsymkey_Load() */
+ if (returnCode == TPM_SUCCESS) {
+ /* save a copy of the HMAC key for the response before changing */
+ TPM_Secret_Copy(saveKey, keyEntity.usageAuth);
+ /* a.The TPM must validate the command using the authorization data entityAuth
+ parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA ->
+ authData. */
+ returnCode = TPM_Auth2data_Check(tpm_state,
+ keyEntity.usageAuth, /* HMAC key */
+ inParamDigest,
+ entity_auth_session_data, /* authorization session */
+ entitynonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueEntitySession,
+ entityAuth); /* Authorization digest for input */
+ }
+ /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth was", keyEntity.usageAuth);
+ TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth now", decryptAuth);
+ TPM_Secret_Copy(keyEntity.usageAuth, decryptAuth);
+ }
+ /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the
+ parentKeyHandle to provide the key information. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey);
+ }
+ }
+ else if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_DATA)) {
+ printf("TPM_Process_ChangeAuth: entityType is TPM_ET_DATA\n");
+ /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or
+ a TPM_SEALED_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ stream = b1DecryptData;
+ stream_size = b1DecryptDataLength;
+ returnCode = TPM_SealedData_Load(&sealEntity, &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: Checking tpmProof\n");
+ returnCode = TPM_Secret_Compare(sealEntity.tpmProof,
+ tpm_state->tpm_permanent_data.tpmProof);
+ }
+ /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */
+ /* NOTE: Done by TPM_SealedData_Load() */
+ if (returnCode == TPM_SUCCESS) {
+ /* save a copy of the HMAC key for the response before changing */
+ TPM_Secret_Copy(saveKey, sealEntity.authData);
+ /* a.The TPM must validate the command using the authorization data entityAuth
+ parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA ->
+ authData. */
+ returnCode = TPM_Auth2data_Check(tpm_state,
+ sealEntity.authData, /* HMAC key */
+ inParamDigest,
+ entity_auth_session_data, /* authorization session */
+ entitynonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueEntitySession,
+ entityAuth); /* Authorization digest for input */
+ }
+ /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuth: authData was", sealEntity.authData);
+ TPM_PrintFour("TPM_Process_ChangeAuth: authData now", decryptAuth);
+ TPM_Secret_Copy(sealEntity.authData, decryptAuth);
+ }
+ /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the
+ parentKeyHandle to provide the key information. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SealedData_GenerateEncData(&outData, &sealEntity, parentKey);
+ }
+ }
+ /* 13. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle
+ sessions. */
+ if (returnCode == TPM_SUCCESS) {
+ continueAuthSession = FALSE;
+ continueEntitySession = FALSE;
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuth: 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;
+ /* 14. The new blob is returned in outData when appropriate. */
+ returnCode = TPM_SizedBuffer_Store(response, &outData);
+ /* 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,
+ *parentHmacKey, /* HMAC key */
+ parent_auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ saveKey, /* the original and not the new auth value */
+ entity_auth_session_data,
+ outParamDigest,
+ entitynonceOdd,
+ continueEntitySession);
+ }
+ /* 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);
+ }
+ /* 15. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle
+ sessions. */
+ if (parentAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, parentAuthHandle);
+ }
+ if (entityAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, entityAuthHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&encData); /* @1 */
+ TPM_SizedBuffer_Delete(&outData); /* @2 */
+ free(b1DecryptData); /* @3 */
+ TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */
+ TPM_SealedData_Delete(&sealEntity); /* @5 */
+ return rcf;
+}
+
+/* 17.2 TPM_ChangeAuthOwner rev 98
+
+ The TPM_ChangeAuthOwner command allows the owner of an entity to change the authorization data
+ for the TPM Owner or the SRK.
+
+ This command requires authorization from the current TPM Owner to execute.
+
+ TPM's targeted for an environment (e.g. a server) with long lasting sessions should not
+ invalidate all sessions.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthOwner(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_PROTOCOL_ID protocolID; /* The protocol in use. */
+ TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_AUTHHANDLE ownerAuthHandle; /* The authorization handle used for the TPM
+ Owner. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with ownerAuthHandle
+ */
+ TPM_BOOL continueAuthSession = TRUE; /* Continue use flag the TPM ignores this value */
+ TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and ownerHandle. HMAC
+ key: tpmOwnerAuth. */
+
+ /* 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 ownerAuthHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *owner_auth_session_data = NULL; /* session data for ownerAuthHandle
+ */
+ TPM_SECRET *hmacKey;
+ TPM_SECRET saveKey; /* copy of HMAC key, since sessions invalidated */
+ TPM_AUTHDATA decryptAuth;
+ TPM_AUTHDATA *entityAuth; /* pointer to either owner or SRK auth */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_ChangeAuthOwner: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get protocolID parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&protocolID, &command, &paramSize);
+ }
+ /* get newAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthOwner: protocolID %04hx\n", protocolID);
+ returnCode = TPM_Authdata_Load(newAuth, &command, &paramSize);
+ }
+ /* get entityType parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&ownerAuthHandle,
+ &ownerAuthHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthOwner: 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) {
+ ownerAuthHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM MUST validate the command using the AuthData in the ownerAuth parameter */
+ /* 2. The ownerAuthHandle session type MUST be TPM_PID_OSAP */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&owner_auth_session_data,
+ &hmacKey,
+ tpm_state,
+ ownerAuthHandle,
+ 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,
+ owner_auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 3. If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */
+ if (returnCode == TPM_SUCCESS) {
+ if (protocolID != TPM_PID_ADCP) {
+ printf("TPM_Process_ChangeAuthOwner: Error, bad protocolID\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 4. Verify that entityType is either TPM_ET_OWNER or TPM_ET_SRK, and return the error
+ TPM_WRONG_ENTITYTYPE if not. */
+ if (returnCode == TPM_SUCCESS) {
+ if (entityType == TPM_ET_OWNER) {
+ printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_OWNER\n");
+ entityAuth = &(tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ else if (entityType == TPM_ET_SRK) {
+ printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_SRK\n");
+ entityAuth = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->usageAuth);
+ }
+ else {
+ entityAuth = NULL; /* just to quiet the compiler */
+ printf("TPM_Process_ChangeAuthOwner: Error, wrong entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* 5. Create decryptAuth by decrypting newAuth according to the ADIP indicated by
+ ownerAuthHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(decryptAuth,
+ NULL,
+ newAuth,
+ owner_auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* even and odd */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuthOwner: From entityAuth", *entityAuth);
+ TPM_PrintFour("TPM_Process_ChangeAuthOwner: To decryptAuth", decryptAuth);
+ /* 6. The TPM MUST enforce the destruction of the ownerAuthHandle session upon completion of
+ this command (successful or unsuccessful). This includes setting continueAuthSession to
+ FALSE */
+ continueAuthSession = FALSE;
+ /* 7. Set the authorization data for the indicated entity to decryptAuth */
+ TPM_Secret_Copy(*entityAuth, decryptAuth);
+ /* save a copy of the HMAC key for the response before invalidating */
+ TPM_Secret_Copy(saveKey, *hmacKey);
+ /* 8. The TPM MUST invalidate all owner authorized OSAP and DSAP sessions, active or
+ saved. */
+ TPM_AuthSessions_TerminateEntity(&continueAuthSession,
+ ownerAuthHandle,
+ tpm_state->tpm_stclear_data.authSessions,
+ TPM_ET_OWNER, /* TPM_ENTITY_TYPE */
+ NULL); /* ignore entityDigest */
+ /* 9. The TPM MAY invalidate all sessions, active or saved */
+ /* Store the permanent data back to 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_ChangeAuthOwner: 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,
+ saveKey, /* HMAC key */
+ owner_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) &&
+ ownerAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, ownerAuthHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+
+/* 27.4.1 TPM_ChangeAuthAsymStart rev 87
+
+ The TPM_ChangeAuthAsymStart starts the process of changing AuthData for an entity. It sets up an
+ OIAP session that must be retained for use by its twin TPM_ChangeAuthAsymFinish command.
+
+ TPM_ChangeAuthAsymStart creates a temporary asymmetric public key "tempkey" to provide
+ confidentiality for new AuthData to be sent to the TPM. TPM_ChangeAuthAsymStart certifies that
+ tempkey was generated by a genuine TPM, by generating a certifyInfo structure that is signed by a
+ TPM identity. The owner of that TPM identity must cooperate to produce this command, because
+ TPM_ChangeAuthAsymStart requires authorization to use that identity.
+
+ It is envisaged that tempkey and certifyInfo are given to the owner of the entity whose
+ authorization is to be changed. That owner uses certifyInfo and a TPM_IDENTITY_CREDENTIAL to
+ verify that tempkey was generated by a genuine TPM. This is done by verifying the
+ TPM_IDENTITY_CREDENTIAL using the public key of a CA, verifying the signature on the certifyInfo
+ structure with the public key of the identity in TPM_IDENTITY_CREDENTIAL, and verifying tempkey
+ by comparing its digest with the value inside certifyInfo. The owner uses tempkey to encrypt the
+ desired new AuthData and inserts that encrypted data in a TPM_ChangeAuthAsymFinish command, in
+ the knowledge that only a TPM with a specific identity can interpret the new AuthData.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthAsymStart(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE idHandle; /* The keyHandle identifier of a loaded identity ID key */
+ TPM_NONCE antiReplay; /* The nonce to be inserted into the certifyInfo structure
+ */
+ TPM_KEY_PARMS tempKeyParms; /* Structure contains all parameters of ephemeral key. */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for idHandle
+ authorization. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session
+ handle */
+ TPM_AUTHDATA idAuth; /* Authorization. HMAC key: idKey.usageAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY *idKey = NULL;
+ TPM_SECRET *idKeyUsageAuth;
+ TPM_BOOL idPCRStatus;
+ TPM_RSA_KEY_PARMS *temp_rsa_key_parms; /* tempKey is RSA */
+ TPM_BOOL key_added = FALSE; /* added to key handle entries */
+ TPM_DIGEST h1Digest;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_CERTIFY_INFO certifyInfo; /* The certifyInfo structure that is to be signed. */
+ TPM_SIZED_BUFFER sig; /* The signature of the certifyInfo parameter. */
+ TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier to be used by
+ ChangeAuthAsymFinish for the ephemeral key */
+ TPM_KEY *tempKey; /* Structure containing all parameters and public part of
+ ephemeral key. TPM_KEY.encSize is set to 0. NOTE
+ Actually tempKey and k1 are the same. The encData is
+ present but not returned in the response. */
+
+ printf("TPM_Process_ChangeAuthAsymStart: Ordinal Entry\n");
+ TPM_KeyParms_Init(&tempKeyParms); /* freed @1 */
+ TPM_CertifyInfo_Init(&certifyInfo); /* freed @2 */
+ TPM_SizedBuffer_Init(&sig); /* freed @3 */
+ tempKey = NULL; /* freed @4 */
+ /*
+ get inputs
+ */
+ /* get idHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&idHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: idHandle %08x\n", idHandle);
+ /* get antiReplay parameter */
+ returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
+ }
+ /* get tempKey (actually tempKeyParms) parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_Load(&tempKeyParms, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ idAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthAsymStart: 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. The TPM SHALL verify the AuthData to use the TPM identity key held in idHandle. The TPM
+ MUST verify that the key is a TPM identity key.*/
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&idKey, &idPCRStatus, tpm_state, idHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (idKey->keyUsage != TPM_KEY_IDENTITY) {
+ printf("TPM_Process_ChangeAuthAsymStart: Error, keyUsage %04hx is invalid\n",
+ idKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){
+ if (idKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_ChangeAuthAsymStart: Error, authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get idHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Key_GetUsageAuth(&idKeyUsageAuth, idKey);
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ idKey,
+ idKeyUsageAuth, /* OIAP */
+ idKey->tpm_store_asymkey->pubDataDigest); /* OSAP */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ idAuth); /* Authorization digest for input */
+ }
+ /* 2. The TPM SHALL validate the algorithm parameters for the key to create from the tempKey
+ parameter. */
+ if (returnCode == TPM_SUCCESS) {
+ /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */
+ /* 3. Recommended key type is RSA */
+ returnCode = TPM_KeyParms_GetRSAKeyParms(&temp_rsa_key_parms, &tempKeyParms);
+ }
+ /* 4. Minimum RSA key size MUST is 512 bits, recommended RSA key size is 1024 */
+ /* 5. For other key types the minimum key size strength MUST be comparable to RSA 512 */
+ /* 6. If the TPM is not designed to create a key of the requested type, return the error code
+ TPM_BAD_KEY_PROPERTY */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_CheckProperties(&tempKeyParms,
+ TPM_KEY_AUTHCHANGE,
+ 0, /* required key length in bits */
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ /* 7. The TPM SHALL create a new key (k1) in accordance with the algorithm parameter. The newly
+ created key is pointed to by ephHandle. */
+ /* NOTE tempKey is used as k1 */
+ /* Allocate space for k1. The key cannot be a local variable, since it persists in key storage
+ after the command completes. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Malloc((unsigned char **)&tempKey, sizeof(TPM_KEY));
+ }
+ /*
+ Field Descriptions for certifyInfo parameter
+ Type Name Description
+ TPM_VERSION Version TPM version structure; Part 2 TPM_VERSION
+ keyFlags Redirection This SHALL be set to FALSE
+ Migratable This SHALL be set to FALSE
+ Volatile This SHALL be set to TRUE
+ TPM_AUTH_DATA_USAGE authDataUsage This SHALL be set to TPM_AUTH_NEVER
+ TPM_KEY_USAGE KeyUsage This SHALL be set to TPM_KEY_AUTHCHANGE
+ uint32_t PCRInfoSize This SHALL be set to 0
+ TPM_DIGEST pubDigest This SHALL be the hash of the public key
+ being certified.
+ TPM_NONCE Data This SHALL be set to antiReplay
+ TPM_KEY_PARMS info This specifies the type of key and its parameters.
+ TPM_BOOL parentPCRStatus This SHALL be set to FALSE.
+ */
+ /* generate a TPM_KEY using TPM_KEY_PARMS. encData is stored as clear text since there is no
+ parent key for the ephemeral key */
+ if (returnCode == TPM_SUCCESS) {
+ /* This must immediately follow the successful malloc, so the _Delete / free work */
+ TPM_Key_Init(tempKey);
+ printf(" TPM_Process_ChangeAuthAsymStart: Creating ephemeral key\n");
+ returnCode = TPM_Key_GenerateRSA(tempKey,
+ tpm_state,
+ NULL, /* encData cleartext */
+ tpm_state->tpm_stclear_data.PCRS, /* PCR array */
+ 1, /* TPM_KEY */
+ TPM_KEY_AUTHCHANGE, /* keyUsage */
+ TPM_ISVOLATILE, /* keyFlags */
+ TPM_AUTH_NEVER, /* authDataUsage */
+ &tempKeyParms, /* TPM_KEY_PARMS */
+ NULL, /* TPM_PCR_INFO */
+ NULL); /* TPM_PCR_INFO_LONG */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ ephHandle = 0; /* no preferred value */
+ returnCode = TPM_KeyHandleEntries_AddKeyEntry(&ephHandle, /* output */
+ tpm_state->tpm_key_handle_entries, /* input */
+ tempKey, /* input */
+ 0, /* parentPCRStatus not used */
+ 0); /* keyControl not used */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: Ephemeral key handle %08x\n", ephHandle);
+ /* remember that the handle has been added to handle list, so it can be deleted on error */
+ key_added = TRUE;
+ }
+ /* 8. The TPM SHALL fill in all fields in tempKey using k1 for the information. The TPM_KEY ->
+ encSize MUST be 0. */
+ /* NOTE Not required. k1 and tempKey are the same */
+ /* 9. The TPM SHALL fill in certifyInfo using k1 for the information. The certifyInfo -> data
+ field is supplied by the antiReplay. */
+ if (returnCode == TPM_SUCCESS) {
+ printf(" TPM_Process_ChangeAuthAsymStart: Creating certifyInfo\n");
+ TPM_Nonce_Copy(certifyInfo.data, antiReplay);
+ returnCode = TPM_CertifyInfo_Set(&certifyInfo, tempKey);
+ }
+ /* 10. The TPM then signs the certifyInfo parameter using the key pointed to by idHandle. The
+ resulting signed blob is returned in sig parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1_GenerateStructure(h1Digest, &certifyInfo,
+ (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: Signing certifyInfo digest\n");
+ returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */
+ h1Digest, /* message */
+ TPM_DIGEST_SIZE, /* message size */
+ idKey); /* input, signing key */
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuthAsymStart: 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 certifyInfo */
+ returnCode = TPM_CertifyInfo_Store(response, &certifyInfo);
+ }
+ /* return sig */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Store(response, &sig);
+ }
+ /* return ephHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append32(response, ephHandle);
+ }
+ /* return tempKey. TPM_Key_StorePubData() does not store any encData. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_StorePubData(response, FALSE, tempKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* TPM_KEY.encSize is set to 0 */
+ returnCode = TPM_Sbuffer_Append32(response, 0);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_KeyParms_Delete(&tempKeyParms); /* @1 */
+ TPM_CertifyInfo_Delete(&certifyInfo); /* @2 */
+ TPM_SizedBuffer_Delete(&sig); /* @3 */
+ /* if there was a failure, delete inKey */
+ if ((rcf != 0) ||
+ (returnCode != TPM_SUCCESS)) {
+ TPM_Key_Delete(tempKey); /* @4 */
+ free(tempKey); /* @4 */
+ if (key_added) {
+ /* if there was a failure and tempKey was stored in the handle list, free the handle.
+ Ignore errors, since only one error code can be returned. */
+ TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, ephHandle);
+ }
+ }
+ return rcf;
+}
+
+/* 27.4.2 TPM_ChangeAuthAsymFinish rev 110
+
+ The TPM_ChangeAuthAsymFinish command allows the owner of an entity to change the AuthData for the
+ entity.
+
+ The command requires the cooperation of the owner of the parent of the entity, since AuthData
+ must be provided to use that parent entity. The command requires knowledge of the existing
+ AuthData information and passes the new AuthData information. The newAuthLink parameter proves
+ knowledge of existing AuthData information and new AuthData information. The new AuthData
+ information "encNewAuth" is encrypted using the "tempKey" variable obtained via
+ TPM_ChangeAuthAsymStart.
+
+ A parent therefore retains control over a change in the AuthData of a child, but is prevented
+ from knowing the new AuthData for that child.
+
+ The changeProof parameter provides a proof that the new AuthData value was properly inserted into
+ the entity. The inclusion of a nonce from the TPM provides an entropy source in the case where
+ the AuthData value may be in itself be a low entropy value (hash of a password etc).
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthAsymFinish(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE parentHandle; /* The keyHandle of the parent key for the input
+ data */
+ TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier for the ephemeral key */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_HMAC newAuthLink; /* HMAC calculation that links the old and new
+ AuthData values together */
+ TPM_SIZED_BUFFER encNewAuth; /* New AuthData encrypted with ephemeral key. */
+ TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */
+ TPM_AUTHHANDLE authHandle; /* Authorization for parent key. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL continueAuthSession; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA privAuth; /* The authorization session digest for inputs and
+ parentHandle. HMAC key: parentKey.usageAuth. */
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY *parentKey = NULL;
+ TPM_SECRET *parentKeyUsageAuth;
+ TPM_BOOL parentPCRStatus;
+ TPM_KEY *ephKey = NULL;
+ TPM_BOOL ephPCRStatus;
+ unsigned char *stream; /* for deserializing decrypted encData */
+ uint32_t stream_size;
+ TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */
+ unsigned char *e1DecryptData;
+ uint32_t e1DecryptDataLength = 0; /* actual valid data */
+ unsigned char *a1Auth;
+ uint32_t a1AuthLength = 0; /* actual valid data */
+ TPM_CHANGEAUTH_VALIDATE changeauthValidate;
+ TPM_BOOL valid;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */
+ TPM_NONCE saltNonce; /* A nonce value from the TPM RNG to add entropy to the
+ changeProof value */
+ TPM_DIGEST changeProof; /* Proof that AuthData has changed. */
+
+ printf("TPM_Process_ChangeAuthAsymFinish: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&encNewAuth); /* freed @1 */
+ TPM_SizedBuffer_Init(&encData); /* freed @2 */
+ TPM_SizedBuffer_Init(&outData); /* freed @3 */
+ TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */
+ e1DecryptData = NULL; /* freed @5 */
+ a1Auth = NULL; /* freed @6 */
+ TPM_ChangeauthValidate_Init(&changeauthValidate); /* freed @7 */
+ /*
+ get inputs
+ */
+ /* get parentHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&parentHandle, &command, &paramSize);
+ }
+ /* get ephHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: parentHandle %08x\n", parentHandle);
+ returnCode = TPM_Load32(&ephHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: ephHandle %08x\n", ephHandle);
+ /* get entityType parameter */
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get newAuthLink parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(newAuthLink, &command, &paramSize);
+ }
+ /* get encNewAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encNewAuth, &command, &paramSize);
+ }
+ /* get encData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: encDataSize %u\n", encData.size);
+ }
+ /* 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_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthAsymFinish: 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. The TPM SHALL validate that the authHandle parameter authorizes use of the key in
+ parentHandle.*/
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus,
+ tpm_state, parentHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){
+ if (parentKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get idHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if (parentHandle != TPM_KH_SRK) {
+ returnCode = TPM_Key_GetUsageAuth(&parentKeyUsageAuth, parentKey);
+ }
+ /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner
+ authorization. */
+ else {
+ parentKeyUsageAuth = &(tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if (parentHandle != TPM_KH_SRK) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ parentKey,
+ parentKeyUsageAuth, /* OIAP */
+ parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/
+ }
+ /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner
+ authorization. */
+ else {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ parentKey,
+ parentKeyUsageAuth, /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /*OSAP*/
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ privAuth); /* Authorization digest for input */
+ }
+ /* 2. The encData field MUST be the encData field from TPM_STORED_DATA or TPM_KEY. */
+ if (returnCode == TPM_SUCCESS) {
+ /* FIXME currently only TPM_KEY supported */
+ if (entityType != TPM_ET_KEY) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, bad entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return the error code
+ TPM_INVALID_KEYUSAGE */
+ if (returnCode == TPM_SUCCESS) {
+ if (parentKey->keyUsage != TPM_KEY_STORAGE) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, keyUsage %04hx is invalid\n",
+ parentKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 3. The TPM SHALL create e1 by decrypting the entity held in the encData parameter. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&e1DecryptData, /* decrypted data */
+ &e1DecryptDataLength, /* actual size of decrypted
+ data */
+ encData.buffer,/* encrypted data */
+ encData.size, /* encrypted data size */
+ parentKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ stream = e1DecryptData;
+ stream_size = e1DecryptDataLength;
+ returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE,
+ &stream, &stream_size,
+ NULL, /* TPM_KEY_PARMS */
+ NULL); /* TPM_SIZED_BUFFER pubKey */
+ }
+ /* 4. The TPM SHALL create a1 by decrypting encNewAuth using the ephHandle ->
+ TPM_KEY_AUTHCHANGE private key. a1 is a structure of type TPM_CHANGEAUTH_VALIDATE. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&ephKey, &ephPCRStatus, tpm_state, ephHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (ephKey->keyUsage != TPM_KEY_AUTHCHANGE) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error: "
+ "ephHandle does not point to TPM_KEY_AUTHCHANGE\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&a1Auth, /* decrypted data */
+ &a1AuthLength, /* actual size of decrypted data */
+ encNewAuth.buffer, /* encrypted data */
+ encNewAuth.size, /* encrypted data size */
+ ephKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ stream = a1Auth;
+ stream_size = a1AuthLength;
+ returnCode = TPM_ChangeauthValidate_Load(&changeauthValidate, &stream, &stream_size);
+ }
+ /* 5. The TPM SHALL create b1 by performing the following HMAC calculation: b1 = HMAC (a1 ->
+ newAuthSecret). The secret for this calculation is encData -> currentAuth. This means that b1
+ is a value built from the current AuthData value (encData -> currentAuth) and the new
+ AuthData value (a1 -> newAuthSecret). */
+ /* 6. The TPM SHALL compare b1 with newAuthLink. The TPM SHALL indicate a failure if the values
+ do not match. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_Check(&valid,
+ newAuthLink, /* expect */
+ keyEntity.usageAuth, /* HMAC key is current auth */
+ TPM_SECRET_SIZE, changeauthValidate.newAuthSecret,
+ 0, NULL);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (!valid) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, authenticating newAuthLink\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 7. The TPM SHALL replace e1 -> authData with a1 -> newAuthSecret */
+ TPM_Secret_Copy(keyEntity.usageAuth, changeauthValidate.newAuthSecret);
+ /* 8. The TPM SHALL encrypt e1 using the appropriate functions for the entity type. The key
+ to encrypt with is parentHandle. */
+ returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey);
+ }
+ /* 9. The TPM SHALL create salt-Nonce by taking the next 20 bytes from the TPM RNG. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Random(saltNonce, TPM_NONCE_SIZE);
+ }
+ /* 10. The TPM SHALL create changeProof a HMAC of (saltNonce concatenated with a1 -> n1) using
+ a1 -> newAuthSecret as the HMAC secret. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_Generate(changeProof, /* hmac output */
+ changeauthValidate.newAuthSecret, /* hmac key */
+ TPM_NONCE_SIZE, saltNonce,
+ TPM_NONCE_SIZE, changeauthValidate.n1,
+ 0, NULL);
+ }
+ /* 11. The TPM MUST destroy the TPM_KEY_AUTHCHANGE key associated with the authorization
+ session. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Deleting ephemeral key\n");
+ TPM_Key_Delete(ephKey); /* free the key resources */
+ free(ephKey); /* free the key itself */
+ /* remove entry from the key handle entries list */
+ returnCode = TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries,
+ ephHandle);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuthAsymFinish: 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 outData */
+ returnCode = TPM_SizedBuffer_Store(response, &outData);
+ }
+ /* return saltNonce */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, saltNonce);
+ }
+ /* return changeProof */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Store(response, changeProof);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&encNewAuth); /* @1 */
+ TPM_SizedBuffer_Delete(&encData); /* @2 */
+ TPM_SizedBuffer_Delete(&outData); /* @3 */
+ TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */
+ free(e1DecryptData); /* @5 */
+ free(a1Auth); /* @6 */
+ TPM_ChangeauthValidate_Delete(&changeauthValidate); /* @7 */
+ return rcf;
+}