/
githubmirror
/
libtpms
Обзор
Документация
Войти
/
githubmirror
/
libtpms
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/tpm12/tpm_auth.c
2 301 строка
85 KB
Stefan Berger
tpm12: Deactivate unused code
01 апр 2019, 17:16
01 апр 2019, 17:16
d0b9d9a
Код
Авторство
О чём код?
/********************************************************************************/ /* */ /* 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(¤tTime, &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, ¶mSize); } /* 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, ¶mSize); } /* get newAuth parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ChangeAuth: protocolID %04hx\n", protocolID); returnCode = TPM_Authdata_Load(newAuth, &command, ¶mSize); } /* get entityType parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load16(&entityType, &command, ¶mSize); } /* get encData parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); } 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, ¶mSize); } /* 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, ¶mSize); } 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, ¶mSize); } /* get newAuth parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ChangeAuthOwner: protocolID %04hx\n", protocolID); returnCode = TPM_Authdata_Load(newAuth, &command, ¶mSize); } /* get entityType parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load16(&entityType, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckRequestTag1(tag); } /* get the 'below the line' authorization parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthParams_Get(&ownerAuthHandle, &ownerAuthHandleValid, nonceOdd, &continueAuthSession, ownerAuth, &command, ¶mSize); } 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, ¶mSize); } /* 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, ¶mSize); } /* get tempKey (actually tempKeyParms) parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyParms_Load(&tempKeyParms, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ &auditStatus, /* output */ &transportEncrypt, /* output */ tpm_state, tag, ordinal, inParamStart, inParamEnd, transportInternal); } /* check state */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); } /* check tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_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, ¶mSize); } 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, ¶mSize); } /* get ephHandle parameter */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ChangeAuthAsymFinish: parentHandle %08x\n", parentHandle); returnCode = TPM_Load32(&ephHandle, &command, ¶mSize); } /* 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, ¶mSize); } /* get newAuthLink parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Digest_Load(newAuthLink, &command, ¶mSize); } /* get encNewAuth parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&encNewAuth, &command, ¶mSize); } /* get encData parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); } 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, ¶mSize); } 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; }