diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
commit | 92cccad89d1c12b39165d5f0ed7ccd2d44965a1a (patch) | |
tree | f59a2764cd8c50959050a428bd8fc935138df750 /src/tpm12 | |
parent | Initial commit. (diff) | |
download | libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.tar.xz libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.zip |
Adding upstream version 0.9.2.upstream/0.9.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
78 files changed, 86033 insertions, 0 deletions
diff --git a/src/tpm12/tpm_admin.c b/src/tpm12/tpm_admin.c new file mode 100644 index 0000000..28d33bb --- /dev/null +++ b/src/tpm12/tpm_admin.c @@ -0,0 +1,2010 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Test and Opt-in */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_admin.c 4505 2011-03-20 17:43:27Z 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 "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_digest.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_ticks.h" +#include "tpm_time.h" + +#include "tpm_admin.h" + +/* The Software TPM Self Test works as follows: + + TPM_LimitedSelfTestCommon(void) - self tests which affect all TPM's + TPM_LimitedSelfTestTPM(tpm_state) - self test per virtual TPM + + TPM_ContinueSelfTestCmd(tpm_state) - currently does nothing + on failure, sets tpm_state->testState to failure for the virtual TPM + + TPM_SelfTestFullCmd(tpm_state) calls + TPM_LimitedSelfTestTPM() + TPM_ContinueSelfTestCmd(tpm_state) + on failure, sets tpm_state->testState to failure for the virtual TPM + + TPM_MainInit(void) calls + TPM_LimitedSelfTestCommon(void) + TPM_LimitedSelfTestTPM(tpm_state) + + TPM_Process_ContinueSelfTest(tpm_state) calls either (depending on FIPS mode) + TPM_SelfTestFullCmd(tpm_state) + TPM_ContinueSelfTestCmd(tpm_state) + + TPM_Process_SelfTestFull(tpm_state) calls + TPM_SelfTestFullCmd(tpm_state) + + The Software TPM assumes that the coprocessor has run self tests before the application code even + begins. So this code doesn't do any real testing of the underlying hardware. This simplifies + the state machine, since TPM_Process_ContinueSelfTest doesn't require a separate thread. +*/ + +/* TPM_LimitedSelfTestCommon() provides the assurance that a selected subset of TPM commands will + perform properly. The limited nature of the self-test allows the TPM to be functional in as short + of time as possible. all the TPM tests. + + The caller is responsible for setting the shutdown state on error. +*/ + +TPM_RESULT TPM_LimitedSelfTestCommon(void) +{ + TPM_RESULT rc = 0; + uint32_t tv_sec; + uint32_t tv_usec; + + printf(" TPM_LimitedSelfTestCommon:\n"); +#if 0 + if (rc == 0) { + rc = TPM_Sbuffer_Test(); + } +#endif + if (rc == 0) { + rc = TPM_Uint64_Test(); + } + if (rc == 0) { + rc = TPM_CryptoTest(); + } + /* test time of day clock */ + if (rc == 0) { + rc = TPM_GetTimeOfDay(&tv_sec, &tv_usec); + } + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + return rc; +} + +TPM_RESULT TPM_LimitedSelfTestTPM(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_NONCE clrData; + TPM_SIZED_BUFFER encData; + TPM_NONCE decData; + uint32_t decLength; + + + printf(" TPM_LimitedSelfTestTPM:\n"); + TPM_SizedBuffer_Init(&encData); /* freed @1 */ + + /* 8. The TPM MUST check the following: */ + /* a. RNG functionality */ + /* NOTE Tested by coprocessor boot */ + /* b. Reading and extending the integrity registers. The self-test for the integrity registers + will leave the integrity registers in a known state. */ + /* NOTE Since there is nothing special about the PCR's, the common TPM_CryptoTest() is + sufficient */ + /* c. Testing the EK integrity, if it exists */ + /* i. This requirement specifies that the TPM will verify that the endorsement key pair can + encrypt and decrypt a known value. This tests the RSA engine. If the EK has not yet been + generated the TPM action is manufacturer specific. */ + if ((rc == 0) && + (tpm_state->tpm_permanent_data.endorsementKey.keyUsage != TPM_KEY_UNINITIALIZED)) { + /* check the key integrity */ + if (rc == 0) { + rc = TPM_Key_CheckPubDataDigest(&(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* encrypt */ + if (rc == 0) { + TPM_Nonce_Generate(clrData); + rc = TPM_RSAPublicEncrypt_Key(&encData, /* output */ + clrData, /* input */ + TPM_NONCE_SIZE, /* input */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* decrypt */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptH(decData, /* decrypted data */ + &decLength, /* length of data put into decrypt_data */ + TPM_NONCE_SIZE, /* size of decrypt_data buffer */ + encData.buffer, + encData.size, + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* verify */ + if (rc == 0) { + if (decLength != TPM_NONCE_SIZE) { + printf("TPM_LimitedSelfTestTPM: Error, decrypt length %u should be %u\n", + decLength, TPM_NONCE_SIZE); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + rc = TPM_Nonce_Compare(clrData, decData); + } + } + /* d. The integrity of the protected capabilities of the TPM */ + /* i. This means that the TPM must ensure that its "microcode" has not changed, and not that a + test must be run on each function. */ + /* e. Any tamper-resistance markers */ + /* i. The tests on the tamper-resistance or tamper-evident markers are under programmable + control. */ + /* There is no requirement to check tamper-evident tape or the status of epoxy surrounding the + case. */ + /* NOTE: Done by coprocessor POST */ + /* 9. The TPM SHOULD check the following: */ + /* a. The hash functionality */ + /* i. This check will hash a known value and compare it to an expected result. There is no + requirement to accept external data to perform the check. */ + /* ii. The TPM MAY support a test using external data. */ + /* NOTE: Done by TPM_CryptoTest() */ + /* b. Any symmetric algorithms */ + /* i. This check will use known data with a random key to encrypt and decrypt the data */ + /* NOTE: Done by TPM_CryptoTest() */ + /* c. Any additional asymmetric algorithms */ + /* i. This check will use known data to encrypt and decrypt. */ + /* NOTE: So far only RSA is supported */ + /* d. The key-wrapping mechanism */ + /* i. The TPM should wrap and unwrap a key. The TPM MUST NOT use the endorsement key pair for + this test. */ + /* NOTE: There is nothing special about serializing a TPM_STORE_ASYMKEY */ + /* e. Any other internal mechanisms */ + TPM_SizedBuffer_Delete(&encData); /* @1 */ + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + /* set the TPM test state */ + if ((rc == 0) && (tpm_state->testState != TPM_TEST_STATE_FAILURE)) { + printf(" TPM_LimitedSelfTestTPM: Set testState to %u \n", TPM_TEST_STATE_LIMITED); + tpm_state->testState = TPM_TEST_STATE_LIMITED; + } + else { + printf(" TPM_LimitedSelfTestTPM: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_ContinueSelfTestCmd() runs the continue self test actions + +*/ + +TPM_RESULT TPM_ContinueSelfTestCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + /* NOTE all done by limited self test */ + printf(" TPM_ContinueSelfTestCmd:\n"); + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + /* set the TPM test state */ + if (rc == 0) { + printf(" TPM_ContinueSelfTestCmd: Set testState to %u \n", TPM_TEST_STATE_FULL); + tpm_state->testState = TPM_TEST_STATE_FULL; + } + else { + printf(" TPM_ContinueSelfTestCmd: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_SelfTestFullCmd is a request to have the TPM perform another complete self-test. This test + will take some time but provides an accurate assessment of the TPM's ability to perform all + operations. + + Runs the actions of self test full. +*/ + +TPM_RESULT TPM_SelfTestFullCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SelfTestFullCmd\n"); + if (rc == 0) { + rc = TPM_LimitedSelfTestTPM(tpm_state); + } + if (rc == 0) { + rc = TPM_ContinueSelfTestCmd(tpm_state); + } + return rc; +} + +/* 4.1 TPM_SelfTestFull rev 88 + + SelfTestFull tests all of the TPM capabilities. + + Unlike TPM_ContinueSelfTest, which may optionally return immediately and then perform the tests, + TPM_SelfTestFull always performs the tests and then returns success or failure. +*/ + +TPM_RESULT TPM_Process_SelfTestFull(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 */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SelfTestFull: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SelfTestFull: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. TPM_SelfTestFull SHALL cause a TPM to perform self-test of each TPM internal function. */ + /* a. If the self-test succeeds, return TPM_SUCCESS. */ + /* b. If the self-test fails, return TPM_FAILEDSELFTEST. */ + /* 2. Failure of any test results in overall failure, and the TPM goes into failure mode. */ + /* 3. If the TPM has not executed the action of TPM_ContinueSelfTest, the TPM */ + /* a. MAY perform the full self-test. */ + /* b. MAY return TPM_NEEDS_SELFTEST. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_SelfTestFull: 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 */ + } + /* 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); + } + return rcf; +} + +/* 4.2 TPM_ContinueSelfTest rev 88 + + TPM_Process_ContinueSelfTest informs the TPM that it may complete the self test of all TPM + functions. + + The TPM may return success immediately and then perform the self-test, or it may perform the + self-test and then return success or failure. + + 1. Prior to executing the actions of TPM_ContinueSelfTest, if the TPM receives a command C1 that + uses an untested TPM function, the TPM MUST take one of these actions: + + a. The TPM MAY return TPM_NEEDS_SELFTEST + + i. This indicates that the TPM has not tested the internal resources required to execute C1. + + ii. The TPM does not execute C1. + + iii. The caller MUST issue TPM_ContinueSelfTest before re-issuing the command C1. + + (1) If the TPM permits TPM_SelfTestFull prior to completing the actions of TPM_ContinueSelfTest, + the caller MAY issue TPM_SelfTestFull rather than TPM_ContinueSelfTest. + + b. The TPM MAY return TPM_DOING_SELFTEST + + i. This indicates that the TPM is doing the actions of TPM_ContinueSelfTest implicitly, as if the + TPM_ContinueSelfTest command had been issued. + + ii. The TPM does not execute C1. + + iii. The caller MUST wait for the actions of TPM_ContinueSelfTest to complete before reissuing + the command C1. + + c. The TPM MAY return TPM_SUCCESS or an error code associated with C1. + + i. This indicates that the TPM has completed the actions of TPM_ContinueSelfTest and has + completed the command C1. + + ii. The error code MAY be TPM_FAILEDSELFTEST. +*/ + +TPM_RESULT TPM_Process_ContinueSelfTest(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 */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ContinueSelfTest: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ContinueSelfTest: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_PERMANENT_FLAGS -> FIPS is TRUE or TPM_PERMANENT_FLAGS -> TPMpost is TRUE */ + if ((tpm_state->tpm_permanent_flags.FIPS) || + (tpm_state->tpm_permanent_flags.TPMpost)) { + /* a. The TPM MUST run ALL self-tests */ + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* 2. Else */ + else { + /* a. The TPM MUST complete all self-tests that are outstanding */ + /* i. Instead of completing all outstanding self-tests the TPM MAY run all self-tests */ + returnCode = TPM_ContinueSelfTestCmd(tpm_state); + } + } + /* 3. The TPM either + a. MAY immediately return TPM_SUCCESS + i. When TPM_ContinueSelfTest finishes execution, it MUST NOT respond to the caller with a + return code. + b. MAY complete the self-test and then return TPM_SUCCESS or TPM_FAILEDSELFTEST. + NOTE Option 3.b. implemented + */ + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_ContinueSelfTest: 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 */ + } + /* 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); + } + return rcf; +} + +/* 4.3 TPM_GetTestResult rev 96 + + TPM_GetTestResult provides manufacturer specific information regarding the results of the self + test. This command will work when the TPM is in self test failure mode. The reason for allowing + this command to operate in the failure mode is to allow TPM manufacturers to obtain diagnostic + information. +*/ + +TPM_RESULT TPM_Process_GetTestResult(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 */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The outData this is manufacturer specific */ + + printf("TPM_Process_GetTestResult: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&outData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + /* This command will work when the TPM is in self test failure or limited operation mode. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_NO_LOCKOUT); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetTestResult: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM SHALL respond to this command with a manufacturer specific block of information + that describes the result of the latest self test. */ + /* 2. The information MUST NOT contain any data that uniquely identifies an individual TPM. */ + /* allocate some reasonable area */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Allocate(&outData, 128); + } + /* for now, just return the state of shutdown as a printable string */ + if (returnCode == TPM_SUCCESS) { + size_t len = outData.size; + /* cast because TPM_SIZED_BUFFER is typically unsigned (binary) but snprintf expects char */ + outData.size = snprintf((char *)(outData.buffer), len, + "Shutdown %08x\n", tpm_state->testState); + if (outData.size >= len) { + printf("TPM_Process_GetTestResult: Error (fatal), buffer too small\n"); + returnCode = TPM_FAIL; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetTestResult: 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); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&outData); /* @1 */ + return rcf; +} + +/* 5.1 TPM_SetOwnerInstall rev 100 + + When enabled but without an owner this command sets the PERMANENT flag that allows or disallows + the ability to insert an owner. + */ + +TPM_RESULT TPM_Process_SetOwnerInstall(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_BOOL state; /* State to which ownership flag is to be set. */ + + /* 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 writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOwnerInstall: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&state, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOwnerInstall: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If the TPM has a current owner, this command immediately returns with TPM_SUCCESS. */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_SetOwnerInstall: Already current owner\n"); + } + /* If the TPM does not have a current owner */ + else { + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerInstall: No current owner\n"); + /* 2. The TPM validates the assertion of physical presence. The TPM then sets the + value of TPM_PERMANENT_FLAGS -> ownership to the value in state. + */ + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_SetOwnerInstall: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerInstall: Setting ownership to %02x\n", state); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.ownership), /* flag */ + state); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOwnerInstall: 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 */ + } + /* 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); + } + return rcf; +} + +/* 5.2 TPM_OwnerSetDisable rev 107 + + The TPM owner sets the PERMANENT disable flag to TRUE or FALSE. +*/ + +TPM_RESULT TPM_Process_OwnerSetDisable(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_BOOL disableState; /* Value for disable state */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerSetDisable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get disableState parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&disableState, &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_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerSetDisable: 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 authenticate the command as coming from the TPM Owner. If unsuccessful, the + TPM SHALL return TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS -> disable flag to the value in the + disableState parameter. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OwnerSetDisable: Setting disable to %u\n", disableState); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable), /* flag */ + disableState); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerSetDisable: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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, 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); + } + return rcf; +} + +/* 5.3 TPM_PhysicalEnable rev 87 + + Sets the PERMANENT disable flag to FALSE using physical presence as authorization. +*/ + +TPM_RESULT TPM_Process_PhysicalEnable(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 */ + + /* 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 writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalEnable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalEnable: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalEnable: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.disable value to FALSE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalEnable: Setting disable to FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable), /* flag */ + FALSE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalEnable: 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 */ + } + /* 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); + } + return rcf; +} + +/* 5.4 TPM_PhysicalDisable rev 87 + + Sets the PERMANENT disable flag to TRUE using physical presence as authorization +*/ + +TPM_RESULT TPM_Process_PhysicalDisable(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 */ + + /* 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 writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalDisable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalDisable: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalDisable: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.disable value to TRUE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalDisable: Setting disable to TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable ), /* flag */ + TRUE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalDisable: 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 */ + } + /* 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); + } + return rcf; +} + +/* 5.5 TPM_PhysicalSetDeactivated rev 105 + + Changes the TPM persistent deactivated flag using physical presence as authorization. +*/ + +TPM_RESULT TPM_Process_PhysicalSetDeactivated(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_BOOL state; /* State to which deactivated flag is to be set. */ + + /* 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 writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalSetDeactivated: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get state parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&state, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalSetDeactivated: state %02x\n", state); + } + /* 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_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalSetDeactivated: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalSetDeactivated: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.deactivated flag to the value in the state + parameter. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalSetDeactivated: Setting deactivated to %u\n", state); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.deactivated), /* flag */ + state); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalSetDeactivated: 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 */ + } + /* 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); + } + return rcf; +} + +/* 5.6 TPM_SetTempDeactivated rev 87 + + This command allows the operator of the platform to deactivate the TPM until the next boot of the + platform. + + This command requires operator authorization. The operator can provide the authorization by + either the assertion of physical presence or presenting the operation authorization value. +*/ + +TPM_RESULT TPM_Process_SetTempDeactivated(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_AUTHHANDLE authHandle; /* auth handle for operation validation. Session type must + be OIAP. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA operatorAuth; /* HMAC key: operatorAuth */ + + /* 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; +#if TPM_V12 + TPM_BOOL physicalPresence; +#endif + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetTempDeactivated: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ACTIVATED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { +#if TPM_V12 + returnCode = TPM_CheckRequestTag10(tag); +#else /* v1.1 is always auth0. This check implicitly bypasses the operatorAuth Actions below. */ + returnCode = TPM_CheckRequestTag0(tag); +#endif + } + /* 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, + operatorAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetTempDeactivated: 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. If tag = TPM_TAG_REQ_AUTH1_COMMAND */ + /* a. If TPM_PERMANENT_FLAGS -> operator is FALSE return TPM_NOOPERATOR */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + if (!tpm_state->tpm_permanent_flags.tpmOperator) { + printf("TPM_Process_SetTempDeactivated: Error, no operator\n"); + returnCode = TPM_NOOPERATOR; + } + } + /* b. Validate command and parameters using operatorAuth, on error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf(" TPM_Process_SetTempDeactivated: authHandle %08x\n", authHandle); + /* get the session data */ + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OIAP, + 0, /* OSAP entity type */ + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.operatorAuth), /* OIAP */ + NULL); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* operator HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + operatorAuth); /* Authorization digest for input */ + + } +#if TPM_V12 /* v1.1 does not require physical presence */ + /* 2. Else */ + /* a. If physical presence is not asserted the TPM MUST return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (!physicalPresence) { + printf("TPM_Process_SetTempDeactivated: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } +#endif + /* 3. The TPM SHALL set the TPM_STCLEAR_FLAGS.deactivated flag to the value TRUE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetTempDeactivated: Setting deactivated to TRUE\n"); + tpm_state->tpm_stclear_flags.deactivated = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetTempDeactivated: 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) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* operator HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 5.7 TPM_SetOperatorAuth rev 87 + + This command allows the setting of the operator authorization value. + + There is no confidentiality applied to the operator authorization as the value is sent under the + assumption of being local to the platform. If there is a concern regarding the path between the + TPM and the keyboard then unless the keyboard is using encryption and a secure channel an + attacker can read the values. +*/ + +TPM_RESULT TPM_Process_SetOperatorAuth(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_SECRET operatorAuth; /* The operator authorization */ + + /* 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 writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOperatorAuth: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get operatorAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Secret_Load(operatorAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOperatorAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If physical presence is not asserted the TPM MUST return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_SetOperatorAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 2. The TPM SHALL set the TPM_PERSISTENT_DATA -> operatorAuth */ + TPM_Digest_Copy(tpm_state->tpm_permanent_data.operatorAuth, operatorAuth); + /* 3. The TPM SHALL set TPM_PERMANENT_FLAGS -> operator to TRUE */ + printf("TPM_Process_SetOperatorAuth: Setting operator to TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.tpmOperator), /* flag */ + TRUE); /* value */ + /* Store the permanent data and flags 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_SetOperatorAuth: 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 */ + } + /* 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); + } + return rcf; +} + +/* 9.3 TPM_ResetLockValue rev 96 + + Command that resets the TPM dictionary attack mitigation values + + This allows the TPM owner to cancel the effect of a number of successive authorization failures. + + If this command itself has an authorization failure, it is blocked for the remainder of the lock + out period. This prevents a dictionary attack on the owner authorization using this command. + + It is understood that this command allows the TPM owner to perform a dictionary attack on other + authorization values by alternating a trial and this command. Similarly, delegating this command + allows the owner's delegate to perform a dictionary attack. +*/ + +TPM_RESULT TPM_Process_ResetLockValue(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_AUTHHANDLE authHandle; /* The authorization session handle used for TPM Owner + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key TPM Owner auth */ + + /* 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; /* session data for authHandle */ + TPM_SECRET *hmacKey; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ResetLockValue: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + /* Update disableResetLock. Ignore the return code since this command is not locked out */ + TPM_Authdata_CheckState(tpm_state); + /* NOTE No TPM_CHECK_NO_LOCKOUT, since this command proceeds anyway */ + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_ACTIVATED | + TPM_CHECK_OWNER)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ResetLockValue: 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. If TPM_STCLEAR_DATA -> disableResetLock is TRUE return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_data.disableResetLock) { + printf("TPM_Process_ResetLockValue: Error, command locked out\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* a. The internal dictionary attack mechanism will set TPM_STCLEAR_DATA -> disableResetLock to + FALSE when the timeout period expires */ + /* NOTE Done by TPM_Authdata_CheckState() */ + /* Validate the parameters and owner authorization for this command */ + if (returnCode == TPM_SUCCESS) { + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. If the the command and parameters validation using ownerAuth fails */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_ResetLockValue: Error, disabling ordinal\n"); + /* a. Set TPM_STCLEAR_DATA -> disableResetLock to TRUE */ + tpm_state->tpm_stclear_data.disableResetLock = TRUE; + /* b. Restart the TPM dictionary attack lock out period */ + /* A failure restarts it anyway with double the period.*/ + /* c. Return TPM_AUTHFAIL */ + } + } + /* 3. Reset the internal TPM dictionary attack mitigation mechanism */ + /* a. The mechanism is vendor specific and can include time outs, reboots, and other mitigation + strategies */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ResetLockValue: Resetting the failure counter\n"); + /* clear the authorization failure counter */ + tpm_state->tpm_stclear_data.authFailCount = 0; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ResetLockValue: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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, 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); + } + return rcf; +} + diff --git a/src/tpm12/tpm_admin.h b/src/tpm12/tpm_admin.h new file mode 100644 index 0000000..f162ee4 --- /dev/null +++ b/src/tpm12/tpm_admin.h @@ -0,0 +1,141 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Test and Opt-in */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_admin.h 4403 2011-02-08 18:28:22Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_ADMIN_H +#define TPM_ADMIN_H + +#include "tpm_types.h" +#include "tpm_global.h" +#include "tpm_store.h" + +TPM_RESULT TPM_LimitedSelfTestCommon(void); +TPM_RESULT TPM_LimitedSelfTestTPM(tpm_state_t *tpm_state); + +TPM_RESULT TPM_ContinueSelfTestCmd(tpm_state_t *tpm_state); +TPM_RESULT TPM_SelfTestFullCmd(tpm_state_t *tpm_state); + +TPM_RESULT TPM_Process_ContinueSelfTest(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 TPM_Process_SelfTestFull(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 TPM_Process_GetTestResult(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 TPM_Process_SetOwnerInstall(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 TPM_Process_OwnerSetDisable(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 TPM_Process_PhysicalDisable(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 TPM_Process_PhysicalEnable(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 TPM_Process_PhysicalSetDeactivated(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 TPM_Process_SetTempDeactivated(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 TPM_Process_SetOperatorAuth(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 TPM_Process_ResetLockValue(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); + +#endif diff --git a/src/tpm12/tpm_audit.c b/src/tpm12/tpm_audit.c new file mode 100644 index 0000000..529dee3 --- /dev/null +++ b/src/tpm12/tpm_audit.c @@ -0,0 +1,1271 @@ +/********************************************************************************/ +/* */ +/* Audit Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_audit.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 "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" + +#include "tpm_audit.h" + +/* + TPM_AUDIT_EVENT_IN +*/ + +/* TPM_AuditEventIn_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuditEventIn_Init(TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + printf(" TPM_AuditEventIn_Init:\n"); + TPM_Digest_Init(tpm_audit_event_in->inputParms); + TPM_CounterValue_Init(&(tpm_audit_event_in->auditCount)); + return; +} + +/* TPM_AuditEventIn_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuditEventIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuditEventIn_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_AUDIT_EVENT_IN); + } + /* store inputParms */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_audit_event_in->inputParms); + } + /* store auditCount */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, &(tpm_audit_event_in->auditCount)); + } + return rc; +} + +/* TPM_AuditEventIn_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuditEventIn_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuditEventIn_Delete(TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + printf(" TPM_AuditEventIn_Delete:\n"); + if (tpm_audit_event_in != NULL) { + TPM_AuditEventIn_Init(tpm_audit_event_in); + } + return; +} + +/* + TPM_AUDIT_EVENT_OUT +*/ + +/* TPM_AuditEventOut_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuditEventOut_Init(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + printf(" TPM_AuditEventOut_Init:\n"); + TPM_Digest_Init(tpm_audit_event_out->outputParms); + TPM_CounterValue_Init(&(tpm_audit_event_out->auditCount)); + return; +} + +/* TPM_AuditEventOut_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuditEventOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuditEventOut_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_AUDIT_EVENT_OUT); + } + /* store outputParms */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_audit_event_out->outputParms); + } + /* store auditCount */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, &(tpm_audit_event_out->auditCount)); + } + return rc; +} + +/* TPM_AuditEventOut_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuditEventOut_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuditEventOut_Delete(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + printf(" TPM_AuditEventOut_Delete:\n"); + if (tpm_audit_event_out != NULL) { + TPM_AuditEventOut_Init(tpm_audit_event_out); + } + return; +} + +/* + ordinalAuditStatus Processing +*/ + +/* TPM_OrdinalAuditStatus_Init() initializes the TPM_PERMANENT_DATA 'ordinalAuditStatus' to the + default + + The flags are stored as a bit map to conserve NVRAM. + + The array is not written back to NVRAM. +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_Init(TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + TPM_COMMAND_CODE ord; /* iterate through all ordinals */ + TPM_BOOL auditDefault; /* result for an ordinal */ + TPM_BOOL altered; + + printf(" TPM_OrdinalAuditStatus_Init:\n"); + + for (ord = 0 ; (rc == 0) && (ord < TPM_ORDINALS_MAX) ; ord++) { + /* get the default audit state from the ordinals table */ + TPM_OrdinalTable_GetAuditDefault(&auditDefault, ord); + /* write to the TPM_PERMANENT_DATA bit map */ + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, ord); + } + /* hack for TSC ordinals */ + if (rc == 0) { + TPM_OrdinalTable_GetAuditDefault(&auditDefault, TSC_ORD_PhysicalPresence); + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, + TSC_ORD_PhysicalPresence); + } + if (rc == 0) { + TPM_OrdinalTable_GetAuditDefault(&auditDefault, TSC_ORD_ResetEstablishmentBit); + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, + TSC_ORD_ResetEstablishmentBit); + } + return rc; +} + +/* TPM_OrdinalAuditStatus_Store() stores a list of all ordinals being audited + */ + +TPM_RESULT TPM_OrdinalAuditStatus_Store(TPM_SIZED_BUFFER *ordinalList, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_COMMAND_CODE startOrdinal) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + TPM_COMMAND_CODE ord; + TPM_BOOL auditStatus; + + printf(" TPM_OrdinalAuditStatus_Store\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* scan through the ordinals array */ + for (ord = startOrdinal ; (rc == 0) && (ord < TPM_ORDINALS_MAX) ; ord++ ) { + /* determine if the ordinal being audited */ + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, ord, tpm_permanent_data); + } + /* if being audited */ + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, ord); /* append ordinal to the list */ + } + } + /* scan the TSC ordinals */ + if (rc == 0) { + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + TSC_ORD_PhysicalPresence, + tpm_permanent_data); + } + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, TSC_ORD_PhysicalPresence); + } + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + TSC_ORD_ResetEstablishmentBit, + tpm_permanent_data); + } + /* if being audited */ + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, TSC_ORD_ResetEstablishmentBit); + } + } + /* convert the list to a TPM_SIZED_BUFFER */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(ordinalList, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_OrdinalAuditStatus_GetAuditState() gets the audit state for the ordinal + */ + +TPM_RESULT TPM_OrdinalAuditStatus_GetAuditStatus(TPM_BOOL *auditStatus, + TPM_COMMAND_CODE ordinal, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + size_t index; /* index of ordinal in array */ + unsigned int offset; /* bit position of ordinal in array */ + unsigned char bit; + + if (rc == 0) { + /* handle the TPM ordinals */ + if (ordinal < TPM_ORDINALS_MAX) { + index = ordinal/CHAR_BIT; + offset = ordinal % CHAR_BIT; + bit = 0x01 << offset; + *auditStatus = tpm_permanent_data->ordinalAuditStatus[index] & bit; + } + /* handle the TSC ordinals */ + else if (ordinal == TSC_ORD_PhysicalPresence) { + *auditStatus = tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT; + } + else if (ordinal == TSC_ORD_ResetEstablishmentBit) { + *auditStatus = tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT; + } + else { + printf("TPM_OrdinalAuditStatus_GetAuditStatus: Error (fatal) " + "ordinal %08x out of range\n", ordinal); + rc = TPM_FAIL; /* should never occur, always called with ordinal processing */ + } + } + /* trace the ordinals with auditing enabled */ + if ((rc == 0) && *auditStatus) { + printf(" TPM_OrdinalAuditStatus_GetAuditStatus: ordinal %08x status %02x\n", + ordinal, *auditStatus); + } + return rc; +} + +/* TPM_OrdinalAuditStatus_SetAuditStatus() sets the TPM_PERMANENT_DATA -> ordinalAuditStatus for the + ordinal + + The flags are stored as a bit map to conserve NVRAM. + + The array is not written back to NVRAM. On error, TPM_PERMANENT_DATA is not changed. + + altered is TRUE if the bit was changed, +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_SetAuditStatus(TPM_BOOL *altered, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL auditStatus, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_BOOL auditable; /* TRUE if the ordinal is auditable by this TPM + implementation */ + size_t index; /* index of ordinal in array */ + unsigned int offset; /* bit position of ordinal in array */ + unsigned char bit; + + *altered = FALSE; /* default, returned on error */ +#if 0 + printf(" TPM_OrdinalAuditStatus_SetAuditStatus: ordinal %08x status %02x\n", + ordinal, auditStatus); +#endif + /* If trying to set, screen against the 'never audit' ordinal table */ + if ((rc == 0) && auditStatus) { + TPM_OrdinalTable_GetAuditable(&auditable, ordinal); + /* if it is a 'never audit' ordinal, it can not be set */ + if (!auditable) { + printf("TPM_OrdinalAuditStatus_SetAuditStatus: " + "Error, cannot audit ordinal %08x\n", ordinal); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + /* handle the TPM ordinals */ + if (ordinal < TPM_ORDINALS_MAX) { + index = ordinal/CHAR_BIT; + offset = ordinal % CHAR_BIT; + bit = 0x01 << offset; + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->ordinalAuditStatus[index] & bit) && !auditStatus) || + (!(tpm_permanent_data->ordinalAuditStatus[index] & bit) && auditStatus)) { + + *altered = TRUE; + } + if (auditStatus) { + /* set the bit */ + tpm_permanent_data->ordinalAuditStatus[index] |= bit; + } + else { + /* clear the bit */ + tpm_permanent_data->ordinalAuditStatus[index] &= ~bit; + } + } + /* handle the TSC ordinals */ + else if (ordinal == TSC_ORD_PhysicalPresence) { + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT) + && !auditStatus) || + (!(tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT) + && auditStatus)) { + + *altered = TRUE; + } + if (auditStatus) { + tpm_permanent_data->tscOrdinalAuditStatus |= TSC_PHYS_PRES_AUDIT; + } + else { + tpm_permanent_data->tscOrdinalAuditStatus &= ~TSC_PHYS_PRES_AUDIT; + } + } + else if (ordinal == TSC_ORD_ResetEstablishmentBit) { + if (auditStatus) { + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT) + && !auditStatus) || + (!(tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT) + && auditStatus)) { + + *altered = TRUE; + } + tpm_permanent_data->tscOrdinalAuditStatus |= TSC_RESET_ESTAB_AUDIT; + } + else { + tpm_permanent_data->tscOrdinalAuditStatus &= ~TSC_RESET_ESTAB_AUDIT; + } + } + else { + printf("TPM_OrdinalAuditStatus_SetAuditStatus: Error ordinal %08x out of range\n", + ordinal); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* + Common Processing Functions +*/ + +/* 8.1 Audit Generation rev 109 + + TPM_AuditDigest_ExtendIn() extends the audit digest with a digest of input parameters +*/ + +TPM_RESULT TPM_AuditDigest_ExtendIn(tpm_state_t *tpm_state, + TPM_DIGEST inParamDigest) +{ + TPM_RESULT rc = 0; + TPM_AUDIT_EVENT_IN tpm_audit_event_in; + TPM_STORE_BUFFER eventIn_sbuffer; + const unsigned char *eventIn_buffer; /* serialized buffer */ + uint32_t eventIn_length; /* serialization length */ + + printf(" TPM_AuditDigest_ExtendIn:\n"); + TPM_AuditEventIn_Init(&tpm_audit_event_in); /* freed @1 */ + TPM_Sbuffer_Init(&eventIn_sbuffer); /* freed @2 */ + + if (rc == 0) { + /* b. Create A1 a TPM_AUDIT_EVENT_IN structure */ + /* NOTE Done by TPM_AuditEventIn_Init() */ + /* i. Set A1 -> inputParms to the digest of the input parameters from the command */ + /* (1) Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + TPM_Digest_Copy(tpm_audit_event_in.inputParms, inParamDigest); + /* ii. Set A1 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + TPM_CounterValue_CopyPublic(&(tpm_audit_event_in.auditCount), + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + /* serialize the A1 TPM_AUDIT_EVENT_IN object */ + rc = TPM_AuditEventIn_Store(&eventIn_sbuffer, &tpm_audit_event_in); + + } + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(&eventIn_sbuffer, &eventIn_buffer, &eventIn_length); + /* c. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A1) */ + TPM_PrintFour(" TPM_AuditDigest_ExtendIn: Previous digest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintAll(" TPM_AuditDigest_ExtendIn: TPM_AUDIT_EVENT_IN", eventIn_buffer, eventIn_length); + rc = TPM_SHA1(tpm_state->tpm_stclear_data.auditDigest, + TPM_DIGEST_SIZE, tpm_state->tpm_stclear_data.auditDigest, + eventIn_length, eventIn_buffer, + 0, NULL); + TPM_PrintFour(" TPM_AuditDigest_ExtendIn: Current digest (in)", + tpm_state->tpm_stclear_data.auditDigest); + } + TPM_AuditEventIn_Delete(&tpm_audit_event_in); /* @1 */ + TPM_Sbuffer_Delete(&eventIn_sbuffer); /* @2 */ + return rc; +} + +/* 8.1 Audit Generation rev 109 + + TPM_AuditDigest_ExtendOut() extends the audit digest with a digest of output parameters +*/ + +TPM_RESULT TPM_AuditDigest_ExtendOut(tpm_state_t *tpm_state, + TPM_DIGEST outParamDigest) +{ + TPM_RESULT rc = 0; + TPM_AUDIT_EVENT_OUT tpm_audit_event_out; + TPM_STORE_BUFFER eventOut_sbuffer; + const unsigned char *eventOut_buffer; /* serialized buffer */ + uint32_t eventOut_length; /* serialization length */ + + printf(" TPM_AuditDigest_ExtendOut:\n"); + TPM_AuditEventOut_Init(&tpm_audit_event_out); /* freed @1 */ + TPM_Sbuffer_Init(&eventOut_sbuffer); /* freed @2 */ + + if (rc == 0) { + /* d. Create A2 a TPM_AUDIT_EVENT_OUT structure */ + /* NOTE Done by TPM_AuditEventOut_Init() */ + /* i. Set A2 -> outputParms to the digest of the output parameters from the command */ + /* (1). Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + TPM_Digest_Copy(tpm_audit_event_out.outputParms, outParamDigest); + /* ii. Set A2 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + TPM_CounterValue_CopyPublic(&(tpm_audit_event_out.auditCount), + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + /* serialize the A2 TPM_AUDIT_EVENT_OUT object */ + rc = TPM_AuditEventOut_Store(&eventOut_sbuffer, &tpm_audit_event_out); + } + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(&eventOut_sbuffer, &eventOut_buffer, &eventOut_length); + /* e. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A2) */ + TPM_PrintFour(" TPM_AuditDigest_ExtendOut: Previous digest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintAll(" TPM_AuditDigest_ExtendOut: TPM_AUDIT_EVENT_OUT", eventOut_buffer, eventOut_length); + rc = TPM_SHA1(tpm_state->tpm_stclear_data.auditDigest, + TPM_DIGEST_SIZE, tpm_state->tpm_stclear_data.auditDigest, + eventOut_length, eventOut_buffer, + 0, NULL); + TPM_PrintFour(" TPM_AuditDigest_ExtendOut: Current digest (out)", + tpm_state->tpm_stclear_data.auditDigest); + } + TPM_AuditEventOut_Delete(&tpm_audit_event_out); /* @1 */ + TPM_Sbuffer_Delete(&eventOut_sbuffer); /* @2 */ + return rc; +} + +/* + Processing Functions +*/ + +/* The TPM generates an audit event in response to the TPM executing a command that has the audit + flag set to TRUE for that command. + + The TPM maintains an extended value for all audited operations. +*/ + +/* 8.3 TPM_GetAuditDigest rev 87 + + This returns the current audit digest. The external audit log has the responsibility to track the + parameters that constitute the audit digest. + + This value may be unique to an individual TPM. The value however will be changing at a rate set + by the TPM Owner. Those attempting to use this value may find it changing without their + knowledge. This value represents a very poor source of tracking uniqueness. +*/ + +TPM_RESULT TPM_Process_GetAuditDigest(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 */ + uint32_t startOrdinal; /* The starting ordinal for the list of audited ordinals */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST auditDigest; /* Log of all audited events */ + TPM_BOOL more; /* TRUE if the output does not contain a full list of + audited ordinals */ + TPM_SIZED_BUFFER ordList; /* List of ordinals that are audited. */ + + printf("TPM_Process_GetAuditDigest: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&ordList); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get startOrdinal parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&startOrdinal, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigest: startOrdinal %08x\n", startOrdinal); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetAuditDigest: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. The TPM sets auditDigest to TPM_STANY_DATA -> auditDigest */ + TPM_Digest_Copy(auditDigest, tpm_state->tpm_stclear_data.auditDigest); + /* 2. The TPM sets counterValue to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* NOTE Since there is only one, use it directly on the output */ + printf("TPM_Process_GetAuditDigest: Counter value %08x\n", + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter); + /* 3. The TPM creates an ordered list of audited ordinals. The list starts at startOrdinal + listing each ordinal that is audited. */ + /* a. If startOrdinal is 0 then the first ordinal that could be audited would be TPM_OIAP + (ordinal 0x0000000A) */ + /* b. The next ordinal would be TPM_OSAP (ordinal 0x0000000B) */ + returnCode = TPM_OrdinalAuditStatus_Store(&ordList, + &(tpm_state->tpm_permanent_data), + startOrdinal); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigest: ordSize %u\n", ordList.size); + /* 4. If the ordered list does not fit in the output buffer the TPM sets more to TRUE */ + more = FALSE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetAuditDigest: 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) { + /* append counterValue */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append counterValue */ + returnCode = TPM_CounterValue_StorePublic + (response, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + /* 5. Return TPM_STANY_DATA -> auditDigest as auditDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, auditDigest); + } + /* append more */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, &more, sizeof(TPM_BOOL)); + } + /* append ordList */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &ordList); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&ordList); /* @1 */ + return rcf; +} + +/* 8.4 TPM_GetAuditDigestSigned rev 101 + + The signing of the audit log returns the entire digest value and the list of currently audited + commands. + + The inclusion of the list of audited commands as an atomic operation is to tie the current digest + value with the list of commands that are being audited. + + Note to future architects + + When auditing functionality is active in a TPM, it may seem logical to remove this ordinal from + the active set of ordinals as the signing functionality of this command could be handled in a + signed transport session. While true this command has a secondary affect also, resetting the + audit log digest. As the reset requires TPM Owner authentication there must be some way in this + command to reflect the TPM Owner wishes. By requiring that a TPM Identity key be the only key + that can sign and reset the TPM Owners authentication is implicit in the execution of the command + (TPM Identity Keys are created and controlled by the TPM Owner only). Hence while one might want + to remove an ordinal this is not one that can be removed if auditing is functional. +*/ + +TPM_RESULT TPM_Process_GetAuditDigestSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key that can perform digital + signatures. */ + TPM_BOOL closeAudit; /* Indication if audit session should be closed */ + TPM_NONCE antiReplay; /* A nonce to prevent replay attacks */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for key + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SIGN_INFO d1SignInfo; + TPM_SIZED_BUFFER d3SizedBuffer; /* List of ordinals that are audited. */ + TPM_STORE_BUFFER d2Sbuffer; /* data to be signed */ + TPM_DIGEST h1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST ordinalDigest; /* Digest of all audited ordinals */ + TPM_SIZED_BUFFER sig; /* The signature of the area */ + + printf("TPM_Process_GetAuditDigestSigned: Ordinal Entry\n"); + TPM_SignInfo_Init(&d1SignInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&d3SizedBuffer); /* freed @2 */ + TPM_Sbuffer_Init(&d2Sbuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get closeAudit parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigestSigned: keyHandle %08x\n", keyHandle); + returnCode = TPM_LoadBool(&closeAudit, &command, ¶mSize); + } + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(antiReplay, &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, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetAuditDigestSigned: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData and parameters using keyAuth, return TPM_AUTHFAIL on error */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetAuditDigestSigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* 2.Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, + if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_IDENTITY) && + (sigKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_GetAuditDigestSigned: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM validates that the key pointed to by keyHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO, return TPM_INVALID_KEYUSAGE on + error */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_GetAuditDigestSigned: Error, invalid sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 4. Create D1 a TPM_SIGN_INFO structure and set the structure defaults */ + /* NOTE Done by TPM_SignInfo_Init() */ + /* a. Set D1 -> fixed to "ADIG" */ + memcpy(d1SignInfo.fixed, "ADIG", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set D1 -> replay to antiReplay */ + TPM_Nonce_Copy(d1SignInfo.replay, antiReplay); + /* c. Create D3 a list of all audited ordinals as defined in the TPM_GetAuditDigest + uint32_t[] ordList outgoing parameter */ + returnCode = TPM_OrdinalAuditStatus_Store(&d3SizedBuffer, + &(tpm_state->tpm_permanent_data), + 0); + } + /* d. Create D4 (ordinalDigest outgoing parameter) the SHA-1 of D3 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(ordinalDigest, + d3SizedBuffer.size, d3SizedBuffer.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* e. Set auditDigest to TPM_STANY_DATA -> auditDigest */ + /* NOTE: Use it directly on the output */ + /* f. Set counterValue to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* NOTE Since there is only one, use it directly on the output */ + /* g. Create D2 the concatenation of auditDigest || counterValue || D4 */ + returnCode = TPM_Sbuffer_Append(&d2Sbuffer, + tpm_state->tpm_stclear_data.auditDigest, TPM_DIGEST_SIZE); + } + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_CounterValue_StorePublic(&d2Sbuffer, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(&d2Sbuffer, + ordinalDigest, TPM_DIGEST_SIZE); + } + /* h. Set D1 -> data to D2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(d1SignInfo.data), &d2Sbuffer); + } + /* i. Create a digital signature of the SHA-1 of D1 by using the signature scheme for keyHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1, &d1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h1, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_GetAuditDigestSigned: auditDigest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintFour("TPM_Process_GetAuditDigestSigned: ordinalDigest", + ordinalDigest); + } + /* j. Set ordinalDigest to D4 */ + /* NOTE Created directly in ordinalDigest */ + /* 5. If closeAudit == TRUE */ + if ((returnCode == TPM_SUCCESS) && closeAudit) { + /* a. If keyHandle->keyUsage is TPM_KEY_IDENTITY */ + if (sigKey->keyUsage == TPM_KEY_IDENTITY) { + /* i. TPM_STANY_DATA -> auditDigest MUST be set to all zeros. */ + TPM_Digest_Init(tpm_state->tpm_stclear_data.auditDigest); + } + /* b. Else */ + else { + /* i. Return TPM_INVALID_KEYUSAGE */ + printf("TPM_Process_GetAuditDigestSigned: Error, " + "cannot closeAudit with keyUsage %04hx\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetAuditDigestSigned: 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 counterValue */ + returnCode = TPM_CounterValue_StorePublic + (response, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + /* return auditDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, tpm_state->tpm_stclear_data.auditDigest); + } + /* return ordinalDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, ordinalDigest); + } + /* return sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SignInfo_Delete(&d1SignInfo); /* @1 */ + TPM_SizedBuffer_Delete(&d3SizedBuffer); /* @2 */ + TPM_Sbuffer_Delete(&d2Sbuffer); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + +/* 8.5 TPM_SetOrdinalAuditStatus rev 109 + + Set the audit flag for a given ordinal. This command requires the authentication of the TPM + Owner. +*/ + +TPM_RESULT TPM_Process_SetOrdinalAuditStatus(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_COMMAND_CODE ordinalToAudit; /* The ordinal whose audit flag is to be set */ + TPM_BOOL auditState; /* Value for audit flag */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL altered; /* status is changing */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOrdinalAuditStatus: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get ordinalToAudit parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&ordinalToAudit, &command, ¶mSize); + } + /* get auditState parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&auditState, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOrdinalAuditStatus: ordinalToAudit %08x auditState %02x\n", + ordinalToAudit, auditState); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOrdinalAuditStatus: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to execute the command and the parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that the ordinal points to a valid TPM ordinal, return TPM_BADINDEX on error */ + /* a. Valid TPM ordinal means an ordinal that the TPM implementation supports */ + /* Done by TPM_OrdinalAuditStatus_SetAuditState() */ + /* 3. Set the non-volatile flag associated with ordinalToAudit to the value in auditState */ + /* NOTE: On error, TPM_PERMANENT_DATA is not changed */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_OrdinalAuditStatus_SetAuditStatus(&altered, + &(tpm_state->tpm_permanent_data), + auditState, /* uninitialized */ + ordinalToAudit); + /* It's not really uninitialized, but beam doesn't understand that TPM_GetInParamDigest() + can't turn a FALSE into a TRUE */ + } + /* Store the permanent data back to NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + altered, + returnCode); + } + /* Audit Generation 3.b. Corner Cases: TPM_SetOrdinalAuditStatus: In the case where the + ordinalToAudit is TPM_ORD_SetOrdinalAuditStatus, audit is based on the initial state, not the + final state. */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOrdinalAuditStatus: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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, 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); + } + return rcf; +} diff --git a/src/tpm12/tpm_audit.h b/src/tpm12/tpm_audit.h new file mode 100644 index 0000000..4bb2e2e --- /dev/null +++ b/src/tpm12/tpm_audit.h @@ -0,0 +1,117 @@ +/********************************************************************************/ +/* */ +/* Audit Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_audit.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_AUDIT_H +#define TPM_AUDIT_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* + TPM_AUDIT_EVENT_IN +*/ + +void TPM_AuditEventIn_Init(TPM_AUDIT_EVENT_IN *tpm_audit_event_in); +TPM_RESULT TPM_AuditEventIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_IN *tpm_audit_event_in); +void TPM_AuditEventIn_Delete(TPM_AUDIT_EVENT_IN *tpm_audit_event_in); + +/* + TPM_AUDIT_EVENT_OUT +*/ + +void TPM_AuditEventOut_Init(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); +TPM_RESULT TPM_AuditEventOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); +void TPM_AuditEventOut_Delete(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); + +/* + ordinalAuditStatus Processing +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_Init(TPM_PERMANENT_DATA *tpm_permanent_data); +TPM_RESULT TPM_OrdinalAuditStatus_Store(TPM_SIZED_BUFFER *ordinalList, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_COMMAND_CODE startOrdinal); +TPM_RESULT TPM_OrdinalAuditStatus_GetAuditStatus(TPM_BOOL *auditStatus, + TPM_COMMAND_CODE ordinal, + TPM_PERMANENT_DATA *tpm_permanent_data); +TPM_RESULT TPM_OrdinalAuditStatus_SetAuditStatus(TPM_BOOL *altered, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL auditStatus, + TPM_COMMAND_CODE ordinal); + +/* + Common Processing Functions +*/ + +TPM_RESULT TPM_AuditDigest_ExtendIn(tpm_state_t *tpm_state, + TPM_DIGEST inParamDigest); +TPM_RESULT TPM_AuditDigest_ExtendOut(tpm_state_t *tpm_state, + TPM_DIGEST outParamDigest); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_GetAuditDigest(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 TPM_Process_GetAuditDigestSigned(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 TPM_Process_SetOrdinalAuditStatus(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); + + +#endif 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(¤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; +} diff --git a/src/tpm12/tpm_auth.h b/src/tpm12/tpm_auth.h new file mode 100644 index 0000000..fba8e6d --- /dev/null +++ b/src/tpm12/tpm_auth.h @@ -0,0 +1,180 @@ +/********************************************************************************/ +/* */ +/* Authorization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_auth.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_AUTH_H +#define TPM_AUTH_H + +#include "tpm_global.h" +#include "tpm_session.h" +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_types.h" + +/* + TPM_AUTHDATA +*/ + +#if 0 +void TPM_Authdata_Init(TPM_AUTHDATA tpm_authdata); +#endif +TPM_RESULT TPM_Authdata_Load(TPM_AUTHDATA tpm_authdata, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Authdata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTHDATA tpm_authdata); + +TPM_RESULT TPM_Authdata_Generate(TPM_AUTHDATA resAuth, + TPM_SECRET usageAuth, + TPM_DIGEST outParamDigest, + TPM_NONCE nonceEven, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession); + +TPM_RESULT TPM_Authdata_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, + TPM_DIGEST inParamDigest, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth); +TPM_RESULT TPM_Auth2data_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, + TPM_DIGEST inParamDigest, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth); + +TPM_RESULT TPM_Authdata_Fail(tpm_state_t *tpm_state); +TPM_RESULT TPM_Authdata_GetState(TPM_DA_STATE *state, + uint32_t *timeLeft, + tpm_state_t *tpm_state); +TPM_RESULT TPM_Authdata_CheckState(tpm_state_t *tpm_state); + +/* + Utilities for command input and output parameter load and store +*/ + +TPM_RESULT TPM_AuthParams_Get(TPM_AUTHHANDLE *authHandle, + TPM_BOOL *authHandleValid, + TPM_NONCE nonceOdd, + TPM_BOOL *continueAuthSession, + TPM_AUTHDATA authData, + unsigned char **command, + uint32_t *paramSize); + +TPM_RESULT TPM_AuthParams_Set(TPM_STORE_BUFFER *response, + TPM_SECRET hmacKey, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_DIGEST outParamDigest, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession); + +/* + TPM_CHANGEAUTH_VALIDATE +*/ + +void TPM_ChangeauthValidate_Init(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); +TPM_RESULT TPM_ChangeauthValidate_Load(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate, + unsigned char **stream, + uint32_t *stream_size); +#if 0 +TPM_RESULT TPM_ChangeauthValidate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); +#endif +void TPM_ChangeauthValidate_Delete(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); + +/* + TPM_DA_INFO +*/ + +void TPM_DaInfo_Init(TPM_DA_INFO *tpm_da_info); +TPM_RESULT TPM_DaInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO *tpm_da_info); +void TPM_DaInfo_Delete(TPM_DA_INFO *tpm_da_info); + +TPM_RESULT TPM_DaInfo_Set(TPM_DA_INFO *tpm_da_info, + tpm_state_t *tpm_state); + +/* + TPM_DA_INFO_LIMITED +*/ + +void TPM_DaInfoLimited_Init(TPM_DA_INFO_LIMITED *tpm_da_info_limited); +TPM_RESULT TPM_DaInfoLimited_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO_LIMITED *tpm_da_info_limited); +void TPM_DaInfoLimited_Delete(TPM_DA_INFO_LIMITED *tpm_da_info_limited); + +TPM_RESULT TPM_DaInfoLimited_Set(TPM_DA_INFO_LIMITED *tpm_da_info_limited, + tpm_state_t *tpm_state); + +/* + Processing functions +*/ + +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 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 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 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); + +#endif diff --git a/src/tpm12/tpm_commands.h b/src/tpm12/tpm_commands.h new file mode 100644 index 0000000..a12c382 --- /dev/null +++ b/src/tpm12/tpm_commands.h @@ -0,0 +1,51 @@ +/********************************************************************************/ +/* */ +/* TPM Command Structure */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_commands.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_COMMANDS_H +#define TPM_COMMANDS_H + +#include "tpm_types.h" + +/* general structure for all commands */ + +#define TPM_TAG_OFFSET 0 +#define TPM_PARAMSIZE_OFFSET (sizeof(TPM_TAG) + TPM_TAG_OFFSET) +#define TPM_ORDINAL_OFFSET (sizeof(uint32_t) + TPM_PARAMSIZE_OFFSET) + +#endif diff --git a/src/tpm12/tpm_constants.h b/src/tpm12/tpm_constants.h new file mode 100644 index 0000000..9569e6d --- /dev/null +++ b/src/tpm12/tpm_constants.h @@ -0,0 +1,1652 @@ +/********************************************************************************/ +/* */ +/* TPM Constants */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_constants.h 4603 2011-08-16 20:40:26Z 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. */ +/********************************************************************************/ + +#ifndef TPM_CONSTANTS_H +#define TPM_CONSTANTS_H + +#include <stdint.h> + +#include <tpm_library_intern.h> + +/* + NOTE implementation Specific +*/ + +/* + version, revision, specLevel, errataRev +*/ + +/* current for released specification revision 103 */ + +#define TPM_REVISION_MAX 9999 +#ifndef TPM_REVISION +#define TPM_REVISION TPM_REVISION_MAX +#endif + +#if (TPM_REVISION >= 116) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x03 /* specification errata level */ + +#elif (TPM_REVISION >= 103) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x02 /* specification errata level */ + +#elif (TPM_REVISION >= 94) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x01 /* specification errata level */ + +#elif (TPM_REVISION >= 85) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x00 /* specification errata level */ + +#else + +#define TPM_SPEC_LEVEL 0x0001 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x00 /* specification errata level */ + +#endif + +/* IBM specific */ + +#if 0 /* at one time vendorID was the PCI vendor ID, this is the IBM code */ +#define TPM_VENDOR_ID "\x00\x00\x10\x14" /* BYTE[4], the vendor ID, obtained from the TCG, + typically PCI vendor ID */ +#endif + + + +#define TPM_VENDOR_ID "IBM" /* 4 bytes, as of rev 99 vendorID and TPM_CAP_PROP_MANUFACTURER + return the same value */ +#define TPM_MANUFACTURER "IBM" /* 4 characters, assigned by TCG, typically stock ticker symbol */ + + +/* Timeouts in microseconds. These are for the platform specific interface (e.g. the LPC bus + registers in the PC Client TPM). They are most likely not applicable to a software TPM. */ +#define TPM_TIMEOUT_A 1000000 +#define TPM_TIMEOUT_B 1000000 +#define TPM_TIMEOUT_C 1000000 +#define TPM_TIMEOUT_D 1000000 + +/* dictionary attack mitigation */ + +#define TPM_LOCKOUT_THRESHOLD 5 /* successive failures to trigger lockout, must be greater + than 0 */ + +/* Denotes the duration value in microseconds of the duration of the three classes of commands: + Small, Medium and Long. The command types are in the Part 2 Ordinal Table. Essentially: + + Long - creating an RSA key pair + Medium - using an RSA key + Short - anything else +*/ + +#ifndef TPM_SMALL_DURATION +#define TPM_SMALL_DURATION 2000000 +#endif + +#ifndef TPM_MEDIUM_DURATION +#define TPM_MEDIUM_DURATION 5000000 +#endif + +#ifndef TPM_LONG_DURATION +#define TPM_LONG_DURATION 60000000 +#endif + +/* startup effects */ + +#define TPM_STARTUP_EFFECTS_VALUE \ +(TPM_STARTUP_EFFECTS_ST_ANY_RT_KEY | /* key resources init by TPM_Startup(ST_ANY) */ \ + TPM_STARTUP_EFFECTS_ST_STATE_RT_HASH | /* hash resources are init by TPM_Startup(ST_STATE) */ \ + TPM_STARTUP_EFFECTS_ST_CLEAR_AUDITDIGEST) /* auditDigest nulled on TPM_Startup(ST_CLEAR) */ + +/* + TPM buffer limits +*/ + +/* This is the increment by which the TPM_STORE_BUFFER grows. A larger number saves realloc's. A + smaller number saves memory. + + TPM_ALLOC_MAX must be a multiple of this value. +*/ + +#define TPM_STORE_BUFFER_INCREMENT (TPM_ALLOC_MAX / 64) + +/* This is the maximum value of the TPM input and output packet buffer. It should be large enough + to accommodate the largest TPM command or response, currently about 1200 bytes. It should be + small enough to accommodate whatever software is driving the TPM. + + NOTE: Some commands are somewhat open ended, and related to this parmater. E.g., The input size + for the TPM_SHA1Init. The output size for TPM_GetRandom. + + It is returned by TPM_GetCapability -> TPM_CAP_PROP_INPUT_BUFFER +*/ + +#ifndef TPM_BUFFER_MAX +#define TPM_BUFFER_MAX 0x1000 /* 4k bytes */ +#endif + +#ifndef TPM_BUFFER_MIN +#define TPM_BUFFER_MIN 0x0c00 /* 3k bytes */ +#endif + +/* Random number generator */ + +/* maximum bytes in one TPM_GetRandom() call + + Use maximum input buffer size minus tag, paramSize, returnCode, randomBytesSize. +*/ + +#define TPM_RANDOM_MAX (TPM12_GetBufferSize() \ + - sizeof(TPM_TAG) - sizeof(uint32_t) \ + - sizeof(TPM_RESULT) - sizeof(uint32_t)) + +/* Maximum number of bytes that can be sent to TPM_SHA1Update. Must be a multiple of 64 bytes. + + Use maximum input buffer size minus tag, paramSize, ordinal, numBytes. +*/ + +#define TPM_SHA1_MAXNUMBYTES (TPM12_GetBufferSize() - 64) + +/* extra audit status bits for TSC commands outside the normal ordinal range */ +#define TSC_PHYS_PRES_AUDIT 0x01 +#define TSC_RESET_ESTAB_AUDIT 0x02 + + +/* TPM_CAP_MFR capabilities */ +#define TPM_CAP_PROCESS_ID 0x00000020 + + +/* define a value for an illegal instance handle */ + +#define TPM_ILLEGAL_INSTANCE_HANDLE 0xffffffff + +/* + NOTE End Implementation Specific +*/ + +/* 3. Structure Tags rev 105 + + There have been some indications that knowing what structure is in use would be valuable + information in each structure. This new tag will be in each new structure that the TPM defines. + + The upper nibble of the value designates the purview of the structure tag. 0 is used for TPM + structures, 1 for platforms, and 2-F are reserved. +*/ + +/* 3.1 TPM_STRUCTURE_TAG */ + +/* Structure */ +#define TPM_TAG_CONTEXTBLOB 0x0001 /* TPM_CONTEXT_BLOB */ +#define TPM_TAG_CONTEXT_SENSITIVE 0x0002 /* TPM_CONTEXT_SENSITIVE */ +#define TPM_TAG_CONTEXTPOINTER 0x0003 /* TPM_CONTEXT_POINTER */ +#define TPM_TAG_CONTEXTLIST 0x0004 /* TPM_CONTEXT_LIST */ +#define TPM_TAG_SIGNINFO 0x0005 /* TPM_SIGN_INFO */ +#define TPM_TAG_PCR_INFO_LONG 0x0006 /* TPM_PCR_INFO_LONG */ +#define TPM_TAG_PERSISTENT_FLAGS 0x0007 /* TPM_PERSISTENT_FLAGS (deprecated 1.1 struct) */ +#define TPM_TAG_VOLATILE_FLAGS 0x0008 /* TPM_VOLATILE_FLAGS (deprecated 1.1 struct) */ +#define TPM_TAG_PERSISTENT_DATA 0x0009 /* TPM_PERSISTENT_DATA (deprecated 1.1 struct) */ +#define TPM_TAG_VOLATILE_DATA 0x000A /* TPM_VOLATILE_DATA (deprecated 1.1 struct) */ +#define TPM_TAG_SV_DATA 0x000B /* TPM_SV_DATA */ +#define TPM_TAG_EK_BLOB 0x000C /* TPM_EK_BLOB */ +#define TPM_TAG_EK_BLOB_AUTH 0x000D /* TPM_EK_BLOB_AUTH */ +#define TPM_TAG_COUNTER_VALUE 0x000E /* TPM_COUNTER_VALUE */ +#define TPM_TAG_TRANSPORT_INTERNAL 0x000F /* TPM_TRANSPORT_INTERNAL */ +#define TPM_TAG_TRANSPORT_LOG_IN 0x0010 /* TPM_TRANSPORT_LOG_IN */ +#define TPM_TAG_TRANSPORT_LOG_OUT 0x0011 /* TPM_TRANSPORT_LOG_OUT */ +#define TPM_TAG_AUDIT_EVENT_IN 0x0012 /* TPM_AUDIT_EVENT_IN */ +#define TPM_TAG_AUDIT_EVENT_OUT 0X0013 /* TPM_AUDIT_EVENT_OUT */ +#define TPM_TAG_CURRENT_TICKS 0x0014 /* TPM_CURRENT_TICKS */ +#define TPM_TAG_KEY 0x0015 /* TPM_KEY */ +#define TPM_TAG_STORED_DATA12 0x0016 /* TPM_STORED_DATA12 */ +#define TPM_TAG_NV_ATTRIBUTES 0x0017 /* TPM_NV_ATTRIBUTES */ +#define TPM_TAG_NV_DATA_PUBLIC 0x0018 /* TPM_NV_DATA_PUBLIC */ +#define TPM_TAG_NV_DATA_SENSITIVE 0x0019 /* TPM_NV_DATA_SENSITIVE */ +#define TPM_TAG_DELEGATIONS 0x001A /* TPM DELEGATIONS */ +#define TPM_TAG_DELEGATE_PUBLIC 0x001B /* TPM_DELEGATE_PUBLIC */ +#define TPM_TAG_DELEGATE_TABLE_ROW 0x001C /* TPM_DELEGATE_TABLE_ROW */ +#define TPM_TAG_TRANSPORT_AUTH 0x001D /* TPM_TRANSPORT_AUTH */ +#define TPM_TAG_TRANSPORT_PUBLIC 0X001E /* TPM_TRANSPORT_PUBLIC */ +#define TPM_TAG_PERMANENT_FLAGS 0X001F /* TPM_PERMANENT_FLAGS */ +#define TPM_TAG_STCLEAR_FLAGS 0X0020 /* TPM_STCLEAR_FLAGS */ +#define TPM_TAG_STANY_FLAGS 0X0021 /* TPM_STANY_FLAGS */ +#define TPM_TAG_PERMANENT_DATA 0X0022 /* TPM_PERMANENT_DATA */ +#define TPM_TAG_STCLEAR_DATA 0X0023 /* TPM_STCLEAR_DATA */ +#define TPM_TAG_STANY_DATA 0X0024 /* TPM_STANY_DATA */ +#define TPM_TAG_FAMILY_TABLE_ENTRY 0X0025 /* TPM_FAMILY_TABLE_ENTRY */ +#define TPM_TAG_DELEGATE_SENSITIVE 0X0026 /* TPM_DELEGATE_SENSITIVE */ +#define TPM_TAG_DELG_KEY_BLOB 0X0027 /* TPM_DELG_KEY_BLOB */ +#define TPM_TAG_KEY12 0x0028 /* TPM_KEY12 */ +#define TPM_TAG_CERTIFY_INFO2 0X0029 /* TPM_CERTIFY_INFO2 */ +#define TPM_TAG_DELEGATE_OWNER_BLOB 0X002A /* TPM_DELEGATE_OWNER_BLOB */ +#define TPM_TAG_EK_BLOB_ACTIVATE 0X002B /* TPM_EK_BLOB_ACTIVATE */ +#define TPM_TAG_DAA_BLOB 0X002C /* TPM_DAA_BLOB */ +#define TPM_TAG_DAA_CONTEXT 0X002D /* TPM_DAA_CONTEXT */ +#define TPM_TAG_DAA_ENFORCE 0X002E /* TPM_DAA_ENFORCE */ +#define TPM_TAG_DAA_ISSUER 0X002F /* TPM_DAA_ISSUER */ +#define TPM_TAG_CAP_VERSION_INFO 0X0030 /* TPM_CAP_VERSION_INFO */ +#define TPM_TAG_DAA_SENSITIVE 0X0031 /* TPM_DAA_SENSITIVE */ +#define TPM_TAG_DAA_TPM 0X0032 /* TPM_DAA_TPM */ +#define TPM_TAG_CMK_MIGAUTH 0X0033 /* TPM_CMK_MIGAUTH */ +#define TPM_TAG_CMK_SIGTICKET 0X0034 /* TPM_CMK_SIGTICKET */ +#define TPM_TAG_CMK_MA_APPROVAL 0X0035 /* TPM_CMK_MA_APPROVAL */ +#define TPM_TAG_QUOTE_INFO2 0X0036 /* TPM_QUOTE_INFO2 */ +#define TPM_TAG_DA_INFO 0x0037 /* TPM_DA_INFO */ +#define TPM_TAG_DA_INFO_LIMITED 0x0038 /* TPM_DA_INFO_LIMITED */ +#define TPM_TAG_DA_ACTION_TYPE 0x0039 /* TPM_DA_ACTION_TYPE */ + +/* + SW TPM Tags +*/ + +/* + These tags are used to describe the format of serialized TPM non-volatile state +*/ + +/* These describe the overall format */ + +/* V1 state is the sequence permanent data, permanent flags, owner evict keys, NV defined space */ + +#define TPM_TAG_NVSTATE_V1 0x0001 /* svn revision 4078 */ + +/* These tags describe the TPM_PERMANENT_DATA format */ + +/* For the first release, use the standard TPM_TAG_PERMANENT_DATA tag. Since this tag is never + visible outside the TPM, the tag value can be changed if the format changes. +*/ + +/* These tags describe the TPM_PERMANENT_FLAGS format */ + +/* The TPM_PERMANENT_FLAGS structure changed from rev 94 to 103. Unfortunately, the standard TPM + tag did not change. Define distinguishing values here. +*/ + +#define TPM_TAG_NVSTATE_PF94 0x0001 +#define TPM_TAG_NVSTATE_PF103 0x0002 + +/* This tag describes the owner evict key format */ + +#define TPM_TAG_NVSTATE_OE_V1 0x0001 + +/* This tag describes the NV defined space format */ + +#define TPM_TAG_NVSTATE_NV_V1 0x0001 + +/* V2 added the NV public optimization */ + +#define TPM_TAG_NVSTATE_NV_V2 0x0002 + +/* + These tags are used to describe the format of serialized TPM volatile state +*/ + +/* These describe the overall format */ + +/* V1 state is the sequence TPM Parameters, TPM_STCLEAR_FLAGS, TPM_STANY_FLAGS, TPM_STCLEAR_DATA, + TPM_STANY_DATA, TPM_KEY_HANDLE_ENTRY, SHA1 context(s), TPM_TRANSHANDLE, testState, NV volatile + flags */ + +#define TPM_TAG_VSTATE_V1 0x0001 + +/* This tag defines the TPM Parameters format */ + +#define TPM_TAG_TPM_PARAMETERS_V1 0x0001 + +/* This tag defines the TPM_STCLEAR_FLAGS format */ + +/* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + +#define TPM_TAG_STCLEAR_FLAGS_V1 0x0001 + +/* These tags describe the TPM_STANY_FLAGS format */ + +/* For the first release, use the standard TPM_TAG_STANY_FLAGS tag. Since this tag is never visible + outside the TPM, the tag value can be changed if the format changes. +*/ + +/* This tag defines the TPM_STCLEAR_DATA format */ + +/* V2 deleted the ordinalResponse, responseCount */ + +#define TPM_TAG_STCLEAR_DATA_V2 0X0024 + +/* These tags describe the TPM_STANY_DATA format */ + +/* For the first release, use the standard TPM_TAG_STANY_DATA tag. Since this tag is never visible + outside the TPM, the tag value can be changed if the format changes. +*/ + +/* This tag defines the key handle entries format */ + +#define TPM_TAG_KEY_HANDLE_ENTRIES_V1 0x0001 + +/* This tag defines the SHA-1 context format */ + +#define TPM_TAG_SHA1CONTEXT_OSSL_V1 0x0001 /* for openssl */ + +#define TPM_TAG_SHA1CONTEXT_FREEBL_V1 0x0101 /* for freebl */ + +/* This tag defines the NV index entries volatile format */ + +#define TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1 0x0001 + +/* 4. Types + */ + +/* 4.1 TPM_RESOURCE_TYPE rev 87 */ + +#define TPM_RT_KEY 0x00000001 /* The handle is a key handle and is the result of a LoadKey + type operation */ + +#define TPM_RT_AUTH 0x00000002 /* The handle is an authorization handle. Auth handles come from + TPM_OIAP, TPM_OSAP and TPM_DSAP */ + +#define TPM_RT_HASH 0X00000003 /* Reserved for hashes */ + +#define TPM_RT_TRANS 0x00000004 /* The handle is for a transport session. Transport handles come + from TPM_EstablishTransport */ + +#define TPM_RT_CONTEXT 0x00000005 /* Resource wrapped and held outside the TPM using the context + save/restore commands */ + +#define TPM_RT_COUNTER 0x00000006 /* Reserved for counters */ + +#define TPM_RT_DELEGATE 0x00000007 /* The handle is for a delegate row. These are the internal rows + held in NV storage by the TPM */ + +#define TPM_RT_DAA_TPM 0x00000008 /* The value is a DAA TPM specific blob */ + +#define TPM_RT_DAA_V0 0x00000009 /* The value is a DAA V0 parameter */ + +#define TPM_RT_DAA_V1 0x0000000A /* The value is a DAA V1 parameter */ + +/* 4.2 TPM_PAYLOAD_TYPE rev 87 + + This structure specifies the type of payload in various messages. +*/ + +#define TPM_PT_ASYM 0x01 /* The entity is an asymmetric key */ +#define TPM_PT_BIND 0x02 /* The entity is bound data */ +#define TPM_PT_MIGRATE 0x03 /* The entity is a migration blob */ +#define TPM_PT_MAINT 0x04 /* The entity is a maintenance blob */ +#define TPM_PT_SEAL 0x05 /* The entity is sealed data */ +#define TPM_PT_MIGRATE_RESTRICTED 0x06 /* The entity is a restricted-migration asymmetric key */ +#define TPM_PT_MIGRATE_EXTERNAL 0x07 /* The entity is a external migratable key */ +#define TPM_PT_CMK_MIGRATE 0x08 /* The entity is a CMK migratable blob */ +/* 0x09 - 0x7F Reserved for future use by TPM */ +/* 0x80 - 0xFF Vendor specific payloads */ + +/* 4.3 TPM_ENTITY_TYPE rev 100 + + This specifies the types of entity that are supported by the TPM. + + The LSB is used to indicate the entity type. The MSB is used to indicate the ADIP + encryption scheme when applicable. + + For compatibility with TPM 1.1, this mapping is maintained: + + 0x0001 specifies a keyHandle entity with XOR encryption + 0x0002 specifies an owner entity with XOR encryption + 0x0003 specifies some data entity with XOR encryption + 0x0004 specifies the SRK entity with XOR encryption + 0x0005 specifies a key entity with XOR encryption + + When the entity is not being used for ADIP encryption, the MSB MUST be 0x00. +*/ + +/* TPM_ENTITY_TYPE LSB Values (entity type) */ + +#define TPM_ET_KEYHANDLE 0x01 /* The entity is a keyHandle or key */ +#define TPM_ET_OWNER 0x02 /*0x40000001 The entity is the TPM Owner */ +#define TPM_ET_DATA 0x03 /* The entity is some data */ +#define TPM_ET_SRK 0x04 /*0x40000000 The entity is the SRK */ +#define TPM_ET_KEY 0x05 /* The entity is a key or keyHandle */ +#define TPM_ET_REVOKE 0x06 /*0x40000002 The entity is the RevokeTrust value */ +#define TPM_ET_DEL_OWNER_BLOB 0x07 /* The entity is a delegate owner blob */ +#define TPM_ET_DEL_ROW 0x08 /* The entity is a delegate row */ +#define TPM_ET_DEL_KEY_BLOB 0x09 /* The entity is a delegate key blob */ +#define TPM_ET_COUNTER 0x0A /* The entity is a counter */ +#define TPM_ET_NV 0x0B /* The entity is a NV index */ +#define TPM_ET_OPERATOR 0x0C /* The entity is the operator */ +#define TPM_ET_RESERVED_HANDLE 0x40 /* Reserved. This value avoids collisions with the handle + MSB setting.*/ + +/* TPM_ENTITY_TYPE MSB Values (ADIP encryption scheme) */ + +#define TPM_ET_XOR 0x00 /* XOR */ +#define TPM_ET_AES128_CTR 0x06 /* AES 128 bits in CTR mode */ + +/* 4.4 Handles rev 88 + + Handles provides pointers to TPM internal resources. Handles should provide the ability to locate + a value without collision. + + 1. The TPM MAY order and set a handle to any value the TPM determines is appropriate + + 2. The handle value SHALL provide assurance that collisions SHOULD not occur in 2^24 handles + + 4.4.1 Reserved Key Handles + + The reserved key handles. These values specify specific keys or specific actions for the TPM. +*/ + +/* 4.4.1 Reserved Key Handles rev 87 + + The reserved key handles. These values specify specific keys or specific actions for the TPM. + + TPM_KH_TRANSPORT indicates to TPM_EstablishTransport that there is no encryption key, and that + the "secret" wrapped parameters are actually passed unencrypted. +*/ + +#define TPM_KH_SRK 0x40000000 /* The handle points to the SRK */ +#define TPM_KH_OWNER 0x40000001 /* The handle points to the TPM Owner */ +#define TPM_KH_REVOKE 0x40000002 /* The handle points to the RevokeTrust value */ +#define TPM_KH_TRANSPORT 0x40000003 /* The handle points to the TPM_EstablishTransport static + authorization */ +#define TPM_KH_OPERATOR 0x40000004 /* The handle points to the Operator auth */ +#define TPM_KH_ADMIN 0x40000005 /* The handle points to the delegation administration + auth */ +#define TPM_KH_EK 0x40000006 /* The handle points to the PUBEK, only usable with + TPM_OwnerReadInternalPub */ + +/* 4.5 TPM_STARTUP_TYPE rev 87 + + To specify what type of startup is occurring. +*/ + +#define TPM_ST_CLEAR 0x0001 /* The TPM is starting up from a clean state */ +#define TPM_ST_STATE 0x0002 /* The TPM is starting up from a saved state */ +#define TPM_ST_DEACTIVATED 0x0003 /* The TPM is to startup and set the deactivated flag to + TRUE */ + +/* 4.6 TPM_STARTUP_EFFECTS rev 101 + + This structure lists for the various resources and sessions on a TPM the affect that TPM_Startup + has on the values. + + There are three ST_STATE options for keys (restore all, restore non-volatile, or restore none) + and two ST_CLEAR options (restore non-volatile or restore none). As bit 4 was insufficient to + describe the possibilities, it is deprecated. Software should use TPM_CAP_KEY_HANDLE to + determine which keys are loaded after TPM_Startup. + + 31-9 No information and MUST be FALSE + + 8 TPM_RT_DAA_TPM resources are initialized by TPM_Startup(ST_STATE) + 7 TPM_Startup has no effect on auditDigest + 6 auditDigest is set to all zeros on TPM_Startup(ST_CLEAR) but not on other types of TPM_Startup + 5 auditDigest is set to all zeros on TPM_Startup(any) + 4 TPM_RT_KEY Deprecated, as the meaning was subject to interpretation. (Was:TPM_RT_KEY resources + are initialized by TPM_Startup(ST_ANY)) + 3 TPM_RT_AUTH resources are initialized by TPM_Startup(ST_STATE) + 2 TPM_RT_HASH resources are initialized by TPM_Startup(ST_STATE) + 1 TPM_RT_TRANS resources are initialized by TPM_Startup(ST_STATE) + 0 TPM_RT_CONTEXT session (but not key) resources are initialized by TPM_Startup(ST_STATE) +*/ + + +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_DAA 0x00000100 /* bit 8 */ +#define TPM_STARTUP_EFFECTS_STARTUP_NO_AUDITDIGEST 0x00000080 /* bit 7 */ +#define TPM_STARTUP_EFFECTS_ST_CLEAR_AUDITDIGEST 0x00000040 /* bit 6 */ +#define TPM_STARTUP_EFFECTS_STARTUP_AUDITDIGEST 0x00000020 /* bit 5 */ +#define TPM_STARTUP_EFFECTS_ST_ANY_RT_KEY 0x00000010 /* bit 4 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_AUTH 0x00000008 /* bit 3 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_HASH 0x00000004 /* bit 2 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_TRANS 0x00000002 /* bit 1 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_CONTEXT 0x00000001 /* bit 0 */ + +/* 4.7 TPM_PROTOCOL_ID rev 87 + + This value identifies the protocol in use. +*/ + +#define TPM_PID_NONE 0x0000 /* kgold - added */ +#define TPM_PID_OIAP 0x0001 /* The OIAP protocol. */ +#define TPM_PID_OSAP 0x0002 /* The OSAP protocol. */ +#define TPM_PID_ADIP 0x0003 /* The ADIP protocol. */ +#define TPM_PID_ADCP 0X0004 /* The ADCP protocol. */ +#define TPM_PID_OWNER 0X0005 /* The protocol for taking ownership of a TPM. */ +#define TPM_PID_DSAP 0x0006 /* The DSAP protocol */ +#define TPM_PID_TRANSPORT 0x0007 /*The transport protocol */ + +/* 4.8 TPM_ALGORITHM_ID rev 99 + + This table defines the types of algorithms that may be supported by the TPM. + + The TPM MUST support the algorithms TPM_ALG_RSA, TPM_ALG_SHA, TPM_ALG_HMAC, and TPM_ALG_MGF1 +*/ + +#define TPM_ALG_RSA 0x00000001 /* The RSA algorithm. */ +/* #define TPM_ALG_DES 0x00000002 (was the DES algorithm) */ +/* #define TPM_ALG_3DES 0X00000003 (was the 3DES algorithm in EDE mode) */ +#define TPM_ALG_SHA 0x00000004 /* The SHA1 algorithm */ +#define TPM_ALG_HMAC 0x00000005 /* The RFC 2104 HMAC algorithm */ +#define TPM_ALG_AES128 0x00000006 /* The AES algorithm, key size 128 */ +#define TPM_ALG_MGF1 0x00000007 /* The XOR algorithm using MGF1 to create a string the size + of the encrypted block */ +#define TPM_ALG_AES192 0x00000008 /* AES, key size 192 */ +#define TPM_ALG_AES256 0x00000009 /* AES, key size 256 */ +#define TPM_ALG_XOR 0x0000000A /* XOR using the rolling nonces */ + +/* 4.9 TPM_PHYSICAL_PRESENCE rev 87 + +*/ + +#define TPM_PHYSICAL_PRESENCE_HW_DISABLE 0x0200 /* Sets the physicalPresenceHWEnable to FALSE + */ +#define TPM_PHYSICAL_PRESENCE_CMD_DISABLE 0x0100 /* Sets the physicalPresenceCMDEnable to + FALSE */ +#define TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK 0x0080 /* Sets the physicalPresenceLifetimeLock to + TRUE */ +#define TPM_PHYSICAL_PRESENCE_HW_ENABLE 0x0040 /* Sets the physicalPresenceHWEnable to TRUE + */ +#define TPM_PHYSICAL_PRESENCE_CMD_ENABLE 0x0020 /* Sets the physicalPresenceCMDEnable to TRUE + */ +#define TPM_PHYSICAL_PRESENCE_NOTPRESENT 0x0010 /* Sets PhysicalPresence = FALSE */ +#define TPM_PHYSICAL_PRESENCE_PRESENT 0x0008 /* Sets PhysicalPresence = TRUE */ +#define TPM_PHYSICAL_PRESENCE_LOCK 0x0004 /* Sets PhysicalPresenceLock = TRUE */ + +#define TPM_PHYSICAL_PRESENCE_MASK 0xfc03 /* ~ OR of all above bits */ + +/* 4.10 TPM_MIGRATE_SCHEME rev 103 + + The scheme indicates how the StartMigrate command should handle the migration of the encrypted + blob. +*/ + +#define TPM_MS_MIGRATE 0x0001 /* A public key that can be used with all TPM + migration commands other than 'ReWrap' mode. */ +#define TPM_MS_REWRAP 0x0002 /* A public key that can be used for the ReWrap mode + of TPM_CreateMigrationBlob. */ +#define TPM_MS_MAINT 0x0003 /* A public key that can be used for the Maintenance + commands */ +#define TPM_MS_RESTRICT_MIGRATE 0x0004 /* The key is to be migrated to a Migration + Authority. */ +#define TPM_MS_RESTRICT_APPROVE 0x0005 /* The key is to be migrated to an entity approved by + a Migration Authority using double wrapping */ + +/* 4.11 TPM_EK_TYPE rev 87 + + This structure indicates what type of information that the EK is dealing with. +*/ + +#define TPM_EK_TYPE_ACTIVATE 0x0001 /* The blob MUST be TPM_EK_BLOB_ACTIVATE */ +#define TPM_EK_TYPE_AUTH 0x0002 /* The blob MUST be TPM_EK_BLOB_AUTH */ + +/* 4.12 TPM_PLATFORM_SPECIFIC rev 87 + + This enumerated type indicates the platform specific spec that the information relates to. +*/ + +#define TPM_PS_PC_11 0x0001 /* PC Specific version 1.1 */ +#define TPM_PS_PC_12 0x0002 /* PC Specific version 1.2 */ +#define TPM_PS_PDA_12 0x0003 /* PDA Specific version 1.2 */ +#define TPM_PS_Server_12 0x0004 /* Server Specific version 1.2 */ +#define TPM_PS_Mobile_12 0x0005 /* Mobil Specific version 1.2 */ + +/* 5.8 TPM_KEY_USAGE rev 101 + + This table defines the types of keys that are possible. Each value defines for what operation + the key can be used. Most key usages can be CMKs. See 4.2, TPM_PAYLOAD_TYPE. + + Each key has a setting defining the encryption and signature scheme to use. The selection of a + key usage value limits the choices of encryption and signature schemes. +*/ + +#define TPM_KEY_UNINITIALIZED 0x0000 /* NOTE: Added. This seems like a good place to indicate + that a TPM_KEY structure has not been initialized */ + +#define TPM_KEY_SIGNING 0x0010 /* This SHALL indicate a signing key. The [private] key + SHALL be used for signing operations, only. This means + that it MUST be a leaf of the Protected Storage key + hierarchy. */ + +#define TPM_KEY_STORAGE 0x0011 /* This SHALL indicate a storage key. The key SHALL be used + to wrap and unwrap other keys in the Protected Storage + hierarchy */ + +#define TPM_KEY_IDENTITY 0x0012 /* This SHALL indicate an identity key. The key SHALL be + used for operations that require a TPM identity, only. */ + +#define TPM_KEY_AUTHCHANGE 0X0013 /* This SHALL indicate an ephemeral key that is in use + during the ChangeAuthAsym process, only. */ + +#define TPM_KEY_BIND 0x0014 /* This SHALL indicate a key that can be used for TPM_Bind + and TPM_Unbind operations only. */ + +#define TPM_KEY_LEGACY 0x0015 /* This SHALL indicate a key that can perform signing and + binding operations. The key MAY be used for both signing + and binding operations. The TPM_KEY_LEGACY key type is to + allow for use by applications where both signing and + encryption operations occur with the same key. */ + +#define TPM_KEY_MIGRATE 0x0016 /* This SHALL indicate a key in use for TPM_MigrateKey */ + +/* 5.8.1 TPM_ENC_SCHEME Mandatory Key Usage Schemes rev 99 + + The TPM MUST check that the encryption scheme defined for use with the key is a valid scheme for + the key type, as follows: +*/ + +#define TPM_ES_NONE 0x0001 +#define TPM_ES_RSAESPKCSv15 0x0002 +#define TPM_ES_RSAESOAEP_SHA1_MGF1 0x0003 +#define TPM_ES_SYM_CTR 0x0004 +#define TPM_ES_SYM_OFB 0x0005 + +/* 5.8.1 TPM_SIG_SCHEME Mandatory Key Usage Schemes rev 99 + + The TPM MUST check that the signature scheme defined for use with the key is a valid scheme for + the key type, as follows: +*/ + +#define TPM_SS_NONE 0x0001 +#define TPM_SS_RSASSAPKCS1v15_SHA1 0x0002 +#define TPM_SS_RSASSAPKCS1v15_DER 0x0003 +#define TPM_SS_RSASSAPKCS1v15_INFO 0x0004 + +/* 5.9 TPM_AUTH_DATA_USAGE rev 110 + + The indication to the TPM when authorization sessions for an entity are required. Future + versions may allow for more complex decisions regarding AuthData checking. +*/ + +#define TPM_AUTH_NEVER 0x00 /* This SHALL indicate that usage of the key without + authorization is permitted. */ + +#define TPM_AUTH_ALWAYS 0x01 /* This SHALL indicate that on each usage of the key the + authorization MUST be performed. */ + +#define TPM_NO_READ_PUBKEY_AUTH 0x03 /* This SHALL indicate that on commands that require the TPM to + use the the key, the authorization MUST be performed. For + commands that cause the TPM to read the public portion of the + key, but not to use the key (e.g. TPM_GetPubKey), the + authorization may be omitted. */ + +/* 5.10 TPM_KEY_FLAGS rev 110 + + This table defines the meanings of the bits in a TPM_KEY_FLAGS structure, used in + TPM_STORE_ASYMKEY and TPM_CERTIFY_INFO. + + The value of TPM_KEY_FLAGS MUST be decomposed into individual mask values. The presence of a mask + value SHALL have the effect described in the above table + + On input, all undefined bits MUST be zero. The TPM MUST return an error if any undefined bit is + set. On output, the TPM MUST set all undefined bits to zero. +*/ + +#ifdef TPM_V12 +#define TPM_KEY_FLAGS_MASK 0x0000001f +#else +#define TPM_KEY_FLAGS_MASK 0x00000007 +#endif + +#define TPM_REDIRECTION 0x00000001 /* This mask value SHALL indicate the use of redirected + output. */ + +#define TPM_MIGRATABLE 0x00000002 /* This mask value SHALL indicate that the key is + migratable. */ + +#define TPM_ISVOLATILE 0x00000004 /* This mask value SHALL indicate that the key MUST be + unloaded upon execution of the + TPM_Startup(ST_Clear). This does not indicate that a + non-volatile key will remain loaded across + TPM_Startup(ST_Clear) events. */ + +#define TPM_PCRIGNOREDONREAD 0x00000008 /* When TRUE the TPM MUST NOT check digestAtRelease or + localityAtRelease for commands that read the public + portion of the key (e.g., TPM_GetPubKey) and MAY NOT + check digestAtRelease or localityAtRelease for + commands that use the public portion of the key + (e.g. TPM_Seal) + + When FALSE the TPM MUST check digestAtRelease and + localityAtRelease for commands that read or use the + public portion of the key */ + +#define TPM_MIGRATEAUTHORITY 0x00000010 /* When set indicates that the key is under control of a + migration authority. The TPM MUST only allow the + creation of a key with this flag in + TPM_MA_CreateKey */ + +/* 5.17 TPM_CMK_DELEGATE values rev 89 + + The bits of TPM_CMK_DELEGATE are flags that determine how the TPM responds to delegated requests + to manipulate a certified-migration-key, a loaded key with payload type TPM_PT_MIGRATE_RESTRICTED + or TPM_PT_MIGRATE_EXTERNAL.. + + 26:0 reserved MUST be 0 + + The default value of TPM_CMK_Delegate is zero (0) +*/ + +#define TPM_CMK_DELEGATE_SIGNING 0x80000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_SIGNING */ +#define TPM_CMK_DELEGATE_STORAGE 0x40000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_STORAGE */ +#define TPM_CMK_DELEGATE_BIND 0x20000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_BIND */ +#define TPM_CMK_DELEGATE_LEGACY 0x10000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_LEGACY */ +#define TPM_CMK_DELEGATE_MIGRATE 0x08000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_MIGRATE */ + +/* 6. TPM_TAG (Command and Response Tags) rev 100 + + These tags indicate to the TPM the construction of the command either as input or as output. The + AUTH indicates that there are one or more AuthData values that follow the command + parameters. +*/ + +#define TPM_TAG_RQU_COMMAND 0x00C1 /* A command with no authentication. */ +#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 /* An authenticated command with one authentication + handle */ +#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 /* An authenticated command with two authentication + handles */ +#define TPM_TAG_RSP_COMMAND 0x00C4 /* A response from a command with no authentication + */ +#define TPM_TAG_RSP_AUTH1_COMMAND 0x00C5 /* An authenticated response with one authentication + handle */ +#define TPM_TAG_RSP_AUTH2_COMMAND 0x00C6 /* An authenticated response with two authentication + handles */ + +/* TIS 7.2 PCR Attributes + +*/ + +#define TPM_DEBUG_PCR 16 +#define TPM_LOCALITY_4_PCR 17 +#define TPM_LOCALITY_3_PCR 18 +#define TPM_LOCALITY_2_PCR 19 +#define TPM_LOCALITY_1_PCR 20 + +/* 10.9 TPM_KEY_CONTROL rev 87 + + Attributes that can control various aspects of key usage and manipulation. + + Allows for controlling of the key when loaded and how to handle TPM_Startup issues. +*/ + +#define TPM_KEY_CONTROL_OWNER_EVICT 0x00000001 /* Owner controls when the key is evicted + from the TPM. When set the TPM MUST + preserve key the key across all TPM_Init + invocations. */ + +/* 13.1.1 TPM_TRANSPORT_ATTRIBUTES Definitions */ + +#define TPM_TRANSPORT_ENCRYPT 0x00000001 /* The session will provide encryption using + the internal encryption algorithm */ +#define TPM_TRANSPORT_LOG 0x00000002 /* The session will provide a log of all + operations that occur in the session */ +#define TPM_TRANSPORT_EXCLUSIVE 0X00000004 /* The transport session is exclusive and + any command executed outside the + transport session causes the invalidation + of the session */ + +/* 21.1 TPM_CAPABILITY_AREA rev 115 + + To identify a capability to be queried. +*/ + +#define TPM_CAP_ORD 0x00000001 /* Boolean value. TRUE indicates that the TPM supports + the ordinal. FALSE indicates that the TPM does not + support the ordinal. Unimplemented optional ordinals + and unused (unassigned) ordinals return FALSE. */ +#define TPM_CAP_ALG 0x00000002 /* Boolean value. TRUE means that the TPM supports the + asymmetric algorithm for TPM_Sign, TPM_Seal, + TPM_UnSeal and TPM_UnBind and related commands. FALSE + indicates that the asymmetric algorithm is not + supported for these types of commands. The TPM MAY + return TRUE or FALSE for other than asymmetric + algorithms that it supports. Unassigned and + unsupported algorithm IDs return FALSE.*/ + +#define TPM_CAP_PID 0x00000003 /* Boolean value. TRUE indicates that the TPM supports + the protocol, FALSE indicates that the TPM does not + support the protocol. */ +#define TPM_CAP_FLAG 0x00000004 /* Return the TPM_PERMANENT_FLAGS structure or Return the + TPM_STCLEAR_FLAGS structure */ +#define TPM_CAP_PROPERTY 0x00000005 /* See following table for the subcaps */ +#define TPM_CAP_VERSION 0x00000006 /* TPM_STRUCT_VER structure. The Major and Minor must + indicate 1.1. The firmware revision MUST indicate + 0.0 */ +#define TPM_CAP_KEY_HANDLE 0x00000007 /* A TPM_KEY_HANDLE_LIST structure that enumerates all + key handles loaded on the TPM. */ +#define TPM_CAP_CHECK_LOADED 0x00000008 /* A Boolean value. TRUE indicates that the TPM has + enough memory available to load a key of the type + specified by TPM_KEY_PARMS. FALSE indicates that the + TPM does not have enough memory. */ +#define TPM_CAP_SYM_MODE 0x00000009 /* Subcap TPM_SYM_MODE + A Boolean value. TRUE indicates that the TPM supports + the TPM_SYM_MODE, FALSE indicates the TPM does not + support the mode. */ +#define TPM_CAP_KEY_STATUS 0x0000000C /* Boolean value of ownerEvict. The handle MUST point to + a valid key handle.*/ +#define TPM_CAP_NV_LIST 0x0000000D /* A list of TPM_NV_INDEX values that are currently + allocated NV storage through TPM_NV_DefineSpace. */ +#define TPM_CAP_MFR 0x00000010 /* Manufacturer specific. The manufacturer may provide + any additional information regarding the TPM and the + TPM state but MUST not expose any sensitive + information. */ +#define TPM_CAP_NV_INDEX 0x00000011 /* A TPM_NV_DATA_PUBLIC structure that indicates the + values for the TPM_NV_INDEX. Returns TPM_BADINDEX if + the index is not in the TPM_CAP_NV_LIST list. */ +#define TPM_CAP_TRANS_ALG 0x00000012 /* Boolean value. TRUE means that the TPM supports the + algorithm for TPM_EstablishTransport, + TPM_ExecuteTransport and + TPM_ReleaseTransportSigned. FALSE indicates that for + these three commands the algorithm is not supported." + */ +#define TPM_CAP_HANDLE 0x00000014 /* A TPM_KEY_HANDLE_LIST structure that enumerates all + handles currently loaded in the TPM for the given + resource type. */ +#define TPM_CAP_TRANS_ES 0x00000015 /* Boolean value. TRUE means the TPM supports the + encryption scheme in a transport session for at least + one algorithm.. */ +#define TPM_CAP_AUTH_ENCRYPT 0x00000017 /* Boolean value. TRUE indicates that the TPM supports + the encryption algorithm in OSAP encryption of + AuthData values */ +#define TPM_CAP_SELECT_SIZE 0x00000018 /* Boolean value. TRUE indicates that the TPM supports + the size for the given version. For instance a request + could ask for version 1.1 size 2 and the TPM would + indicate TRUE. For 1.1 size 3 the TPM would indicate + FALSE. For 1.2 size 3 the TPM would indicate TRUE. */ +#define TPM_CAP_DA_LOGIC 0x00000019 /* (OPTIONAL) + A TPM_DA_INFO or TPM_DA_INFO_LIMITED structure that + returns data according to the selected entity type + (e.g., TPM_ET_KEYHANDLE, TPM_ET_OWNER, TPM_ET_SRK, + TPM_ET_COUNTER, TPM_ET_OPERATOR, etc.). If the + implemented dictionary attack logic does not support + different secret types, the entity type can be + ignored. */ +#define TPM_CAP_VERSION_VAL 0x0000001A /* TPM_CAP_VERSION_INFO structure. The TPM fills in the + structure and returns the information indicating what + the TPM currently supports. */ + +#define TPM_CAP_FLAG_PERMANENT 0x00000108 /* Return the TPM_PERMANENT_FLAGS structure */ +#define TPM_CAP_FLAG_VOLATILE 0x00000109 /* Return the TPM_STCLEAR_FLAGS structure */ + +/* 21.2 CAP_PROPERTY Subcap values for CAP_PROPERTY rev 105 + + The TPM_CAP_PROPERTY capability has numerous subcap values. The definition for all subcap values + occurs in this table. + + TPM_CAP_PROP_MANUFACTURER returns a vendor ID unique to each manufacturer. The same value is + returned as the TPM_CAP_VERSION_INFO -> tpmVendorID. A company abbreviation such as a null + terminated stock ticker is a typical choice. However, there is no requirement that the value + contain printable characters. The document "TCG Vendor Naming" lists the vendor ID values. + + TPM_CAP_PROP_MAX_xxxSESS is a constant. At TPM_Startup(ST_CLEAR) TPM_CAP_PROP_xxxSESS == + TPM_CAP_PROP_MAX_xxxSESS. As sessions are created on the TPM, TPM_CAP_PROP_xxxSESS decreases + toward zero. As sessions are terminated, TPM_CAP_PROP_xxxSESS increases toward + TPM_CAP_PROP_MAX_xxxSESS. + + There is a similar relationship between the constants TPM_CAP_PROP_MAX_COUNTERS and + TPM_CAP_PROP_MAX_CONTEXT and the varying TPM_CAP_PROP_COUNTERS and TPM_CAP_PROP_CONTEXT. + + In one typical implementation where authorization and transport sessions reside in separate + pools, TPM_CAP_PROP_SESSIONS will be the sum of TPM_CAP_PROP_AUTHSESS and TPM_CAP_PROP_TRANSESS. + In another typical implementation where authorization and transport sessions share the same pool, + TPM_CAP_PROP_SESSIONS, TPM_CAP_PROP_AUTHSESS, and TPM_CAP_PROP_TRANSESS will all be equal. +*/ + +#define TPM_CAP_PROP_PCR 0x00000101 /* uint32_t value. Returns the number of PCR + registers supported by the TPM */ +#define TPM_CAP_PROP_DIR 0x00000102 /* uint32_t. Deprecated. Returns the number of + DIR, which is now fixed at 1 */ +#define TPM_CAP_PROP_MANUFACTURER 0x00000103 /* uint32_t value. Returns the vendor ID + unique to each TPM manufacturer. */ +#define TPM_CAP_PROP_KEYS 0x00000104 /* uint32_t value. Returns the number of 2048- + bit RSA keys that can be loaded. This may + vary with time and circumstances. */ +#define TPM_CAP_PROP_MIN_COUNTER 0x00000107 /* uint32_t. The minimum amount of time in + 10ths of a second that must pass between + invocations of incrementing the monotonic + counter. */ +#define TPM_CAP_PROP_AUTHSESS 0x0000010A /* uint32_t. The number of available + authorization sessions. This may vary with + time and circumstances. */ +#define TPM_CAP_PROP_TRANSESS 0x0000010B /* uint32_t. The number of available transport + sessions. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_COUNTERS 0x0000010C /* uint32_t. The number of available monotonic + counters. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_MAX_AUTHSESS 0x0000010D /* uint32_t. The maximum number of loaded + authorization sessions the TPM supports */ +#define TPM_CAP_PROP_MAX_TRANSESS 0x0000010E /* uint32_t. The maximum number of loaded + transport sessions the TPM supports. */ +#define TPM_CAP_PROP_MAX_COUNTERS 0x0000010F /* uint32_t. The maximum number of monotonic + counters under control of TPM_CreateCounter + */ +#define TPM_CAP_PROP_MAX_KEYS 0x00000110 /* uint32_t. The maximum number of 2048 RSA + keys that the TPM can support. The number + does not include the EK or SRK. */ +#define TPM_CAP_PROP_OWNER 0x00000111 /* BOOL. A value of TRUE indicates that the + TPM has successfully installed an owner. */ +#define TPM_CAP_PROP_CONTEXT 0x00000112 /* uint32_t. The number of available saved + session slots. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_MAX_CONTEXT 0x00000113 /* uint32_t. The maximum number of saved + session slots. */ +#define TPM_CAP_PROP_FAMILYROWS 0x00000114 /* uint32_t. The maximum number of rows in the + family table */ +#define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115 /* A 4 element array of uint32_t values each + denoting the timeout value in microseconds + for the following in this order: + + TIMEOUT_A, TIMEOUT_B, TIMEOUT_C, TIMEOUT_D + + Where these timeouts are to be used is + determined by the platform specific TPM + Interface Specification. */ +#define TPM_CAP_PROP_STARTUP_EFFECT 0x00000116 /* The TPM_STARTUP_EFFECTS structure */ +#define TPM_CAP_PROP_DELEGATE_ROW 0x00000117 /* uint32_t. The maximum size of the delegate + table in rows. */ +#define TPM_CAP_PROP_MAX_DAASESS 0x00000119 /* uint32_t. The maximum number of loaded DAA + sessions (join or sign) that the TPM + supports */ +#define TPM_CAP_PROP_DAASESS 0x0000011A /* uint32_t. The number of available DAA + sessions. This may vary with time and + circumstances */ +#define TPM_CAP_PROP_CONTEXT_DIST 0x0000011B /* uint32_t. The maximum distance between + context count values. This MUST be at least + 2^16-1. */ +#define TPM_CAP_PROP_DAA_INTERRUPT 0x0000011C /* BOOL. A value of TRUE indicates that the + TPM will accept ANY command while executing + a DAA Join or Sign. + + A value of FALSE indicates that the TPM + will invalidate the DAA Join or Sign upon + the receipt of any command other than the + next join/sign in the session or a + TPM_SaveContext */ +#define TPM_CAP_PROP_SESSIONS 0X0000011D /* uint32_t. The number of available sessions + from the pool. This MAY vary with time and + circumstances. Pool sessions include + authorization and transport sessions. */ +#define TPM_CAP_PROP_MAX_SESSIONS 0x0000011E /* uint32_t. The maximum number of sessions + the TPM supports. */ +#define TPM_CAP_PROP_CMK_RESTRICTION 0x0000011F /* uint32_t TPM_Permanent_Data -> + restrictDelegate + */ +#define TPM_CAP_PROP_DURATION 0x00000120 /* A 3 element array of uint32_t values each + denoting the duration value in microseconds + of the duration of the three classes of + commands: Small, Medium and Long in the + following in this order: SMALL_DURATION, + MEDIUM_DURATION, LONG_DURATION */ +#define TPM_CAP_PROP_ACTIVE_COUNTER 0x00000122 /* TPM_COUNT_ID. The id of the current + counter. 0xff..ff if no counter is active + */ +#define TPM_CAP_PROP_MAX_NV_AVAILABLE 0x00000123 /*uint32_t. Deprecated. The maximum number + of NV space that can be allocated, MAY + vary with time and circumstances. This + capability was not implemented + consistently, and is replaced by + TPM_NV_INDEX_TRIAL. */ +#define TPM_CAP_PROP_INPUT_BUFFER 0x00000124 /* uint32_t. The maximum size of the TPM + input buffer or output buffer in + bytes. */ + +/* 21.4 Set_Capability Values rev 107 + */ + +#define TPM_SET_PERM_FLAGS 0x00000001 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_PERM_DATA 0x00000002 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STCLEAR_FLAGS 0x00000003 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STCLEAR_DATA 0x00000004 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STANY_FLAGS 0x00000005 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STANY_DATA 0x00000006 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_VENDOR 0x00000007 /* This area allows the vendor to set specific areas + in the TPM according to the normal shielded + location requirements */ + +/* Set Capability sub caps */ + +/* TPM_PERMANENT_FLAGS */ + +#define TPM_PF_DISABLE 1 +#define TPM_PF_OWNERSHIP 2 +#define TPM_PF_DEACTIVATED 3 +#define TPM_PF_READPUBEK 4 +#define TPM_PF_DISABLEOWNERCLEAR 5 +#define TPM_PF_ALLOWMAINTENANCE 6 +#define TPM_PF_PHYSICALPRESENCELIFETIMELOCK 7 +#define TPM_PF_PHYSICALPRESENCEHWENABLE 8 +#define TPM_PF_PHYSICALPRESENCECMDENABLE 9 +#define TPM_PF_CEKPUSED 10 +#define TPM_PF_TPMPOST 11 +#define TPM_PF_TPMPOSTLOCK 12 +#define TPM_PF_FIPS 13 +#define TPM_PF_OPERATOR 14 +#define TPM_PF_ENABLEREVOKEEK 15 +#define TPM_PF_NV_LOCKED 16 +#define TPM_PF_READSRKPUB 17 +#define TPM_PF_TPMESTABLISHED 18 +#define TPM_PF_MAINTENANCEDONE 19 +#define TPM_PF_DISABLEFULLDALOGICINFO 20 + +/* TPM_STCLEAR_FLAGS */ + +#define TPM_SF_DEACTIVATED 1 +#define TPM_SF_DISABLEFORCECLEAR 2 +#define TPM_SF_PHYSICALPRESENCE 3 +#define TPM_SF_PHYSICALPRESENCELOCK 4 +#define TPM_SF_BGLOBALLOCK 5 + +/* TPM_STANY_FLAGS */ + +#define TPM_AF_POSTINITIALISE 1 +#define TPM_AF_LOCALITYMODIFIER 2 +#define TPM_AF_TRANSPORTEXCLUSIVE 3 +#define TPM_AF_TOSPRESENT 4 + +/* TPM_PERMANENT_DATA */ + +#define TPM_PD_REVMAJOR 1 +#define TPM_PD_REVMINOR 2 +#define TPM_PD_TPMPROOF 3 +#define TPM_PD_OWNERAUTH 4 +#define TPM_PD_OPERATORAUTH 5 +#define TPM_PD_MANUMAINTPUB 6 +#define TPM_PD_ENDORSEMENTKEY 7 +#define TPM_PD_SRK 8 +#define TPM_PD_DELEGATEKEY 9 +#define TPM_PD_CONTEXTKEY 10 +#define TPM_PD_AUDITMONOTONICCOUNTER 11 +#define TPM_PD_MONOTONICCOUNTER 12 +#define TPM_PD_PCRATTRIB 13 +#define TPM_PD_ORDINALAUDITSTATUS 14 +#define TPM_PD_AUTHDIR 15 +#define TPM_PD_RNGSTATE 16 +#define TPM_PD_FAMILYTABLE 17 +#define TPM_DELEGATETABLE 18 +#define TPM_PD_EKRESET 19 +#define TPM_PD_LASTFAMILYID 21 +#define TPM_PD_NOOWNERNVWRITE 22 +#define TPM_PD_RESTRICTDELEGATE 23 +#define TPM_PD_TPMDAASEED 24 +#define TPM_PD_DAAPROOF 25 + +/* TPM_STCLEAR_DATA */ + +#define TPM_SD_CONTEXTNONCEKEY 1 +#define TPM_SD_COUNTID 2 +#define TPM_SD_OWNERREFERENCE 3 +#define TPM_SD_DISABLERESETLOCK 4 +#define TPM_SD_PCR 5 +#define TPM_SD_DEFERREDPHYSICALPRESENCE 6 + +/* TPM_STCLEAR_DATA -> deferredPhysicalPresence bits */ + +#define TPM_DPP_UNOWNED_FIELD_UPGRADE 0x00000001 /* bit 0 TPM_FieldUpgrade */ + +/* TPM_STANY_DATA */ + +#define TPM_AD_CONTEXTNONCESESSION 1 +#define TPM_AD_AUDITDIGEST 2 +#define TPM_AD_CURRENTTICKS 3 +#define TPM_AD_CONTEXTCOUNT 4 +#define TPM_AD_CONTEXTLIST 5 +#define TPM_AD_SESSIONS 6 + +/* 17. Ordinals rev 110 + + Ordinals are 32 bit values of type TPM_COMMAND_CODE. The upper byte contains values that serve + as flag indicators, the next byte contains values indicating what committee designated the + ordinal, and the final two bytes contain the Command Ordinal Index. + + 3 2 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |P|C|V| Reserved| Purview | Command Ordinal Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Where: + + P is Protected/Unprotected command. When 0 the command is a Protected command, when 1 the + command is an Unprotected command. + + C is Non-Connection/Connection related command. When 0 this command passes through to either the + protected (TPM) or unprotected (TSS) components. + + V is TPM/Vendor command. When 0 the command is TPM defined, when 1 the command is vendor + defined. + + All reserved area bits are set to 0. +*/ + +/* The following masks are created to allow for the quick definition of the commands */ + +#define TPM_PROTECTED_COMMAND 0x00000000 /* TPM protected command, specified in main specification + */ +#define TPM_UNPROTECTED_COMMAND 0x80000000 /* TSS command, specified in the TSS specification */ +#define TPM_CONNECTION_COMMAND 0x40000000 /* TSC command, protected connection commands are + specified in the main specification Unprotected + connection commands are specified in the TSS */ +#define TPM_VENDOR_COMMAND 0x20000000 /* Command that is vendor specific for a given TPM or + TSS. */ + + +/* The following Purviews have been defined: */ + +#define TPM_MAIN 0x00 /* Command is from the main specification */ +#define TPM_PC 0x01 /* Command is specific to the PC */ +#define TPM_PDA 0x02 /* Command is specific to a PDA */ +#define TPM_CELL_PHONE 0x03 /* Command is specific to a cell phone */ +#define TPM_SERVER 0x04 /* Command is specific to servers */ +#define TPM_PERIPHERAL 0x05 /* Command is specific to peripherals */ +#define TPM_TSS 0x06 /* Command is specific to TSS */ + +/* Combinations for the main specification would be: */ + +#define TPM_PROTECTED_ORDINAL (TPM_PROTECTED_COMMAND | TPM_MAIN) +#define TPM_UNPROTECTED_ORDINAL (TPM_UNPROTECTED_COMMAND | TPM_MAIN) +#define TPM_CONNECTION_ORDINAL (TPM_CONNECTION_COMMAND | TPM_MAIN) + +/* Command ordinals */ + +#define TPM_ORD_ActivateIdentity 0x0000007A +#define TPM_ORD_AuthorizeMigrationKey 0x0000002B +#define TPM_ORD_CertifyKey 0x00000032 +#define TPM_ORD_CertifyKey2 0x00000033 +#define TPM_ORD_CertifySelfTest 0x00000052 +#define TPM_ORD_ChangeAuth 0x0000000C +#define TPM_ORD_ChangeAuthAsymFinish 0x0000000F +#define TPM_ORD_ChangeAuthAsymStart 0x0000000E +#define TPM_ORD_ChangeAuthOwner 0x00000010 +#define TPM_ORD_CMK_ApproveMA 0x0000001D +#define TPM_ORD_CMK_ConvertMigration 0x00000024 +#define TPM_ORD_CMK_CreateBlob 0x0000001B +#define TPM_ORD_CMK_CreateKey 0x00000013 +#define TPM_ORD_CMK_CreateTicket 0x00000012 +#define TPM_ORD_CMK_SetRestrictions 0x0000001C +#define TPM_ORD_ContinueSelfTest 0x00000053 +#define TPM_ORD_ConvertMigrationBlob 0x0000002A +#define TPM_ORD_CreateCounter 0x000000DC +#define TPM_ORD_CreateEndorsementKeyPair 0x00000078 +#define TPM_ORD_CreateMaintenanceArchive 0x0000002C +#define TPM_ORD_CreateMigrationBlob 0x00000028 +#define TPM_ORD_CreateRevocableEK 0x0000007F +#define TPM_ORD_CreateWrapKey 0x0000001F +#define TPM_ORD_DAA_Join 0x00000029 +#define TPM_ORD_DAA_Sign 0x00000031 +#define TPM_ORD_Delegate_CreateKeyDelegation 0x000000D4 +#define TPM_ORD_Delegate_CreateOwnerDelegation 0x000000D5 +#define TPM_ORD_Delegate_LoadOwnerDelegation 0x000000D8 +#define TPM_ORD_Delegate_Manage 0x000000D2 +#define TPM_ORD_Delegate_ReadTable 0x000000DB +#define TPM_ORD_Delegate_UpdateVerification 0x000000D1 +#define TPM_ORD_Delegate_VerifyDelegation 0x000000D6 +#define TPM_ORD_DirRead 0x0000001A +#define TPM_ORD_DirWriteAuth 0x00000019 +#define TPM_ORD_DisableForceClear 0x0000005E +#define TPM_ORD_DisableOwnerClear 0x0000005C +#define TPM_ORD_DisablePubekRead 0x0000007E +#define TPM_ORD_DSAP 0x00000011 +#define TPM_ORD_EstablishTransport 0x000000E6 +#define TPM_ORD_EvictKey 0x00000022 +#define TPM_ORD_ExecuteTransport 0x000000E7 +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_FieldUpgrade 0x000000AA +#define TPM_ORD_FlushSpecific 0x000000BA +#define TPM_ORD_ForceClear 0x0000005D +#define TPM_ORD_GetAuditDigest 0x00000085 +#define TPM_ORD_GetAuditDigestSigned 0x00000086 +#define TPM_ORD_GetAuditEvent 0x00000082 +#define TPM_ORD_GetAuditEventSigned 0x00000083 +#define TPM_ORD_GetCapability 0x00000065 +#define TPM_ORD_GetCapabilityOwner 0x00000066 +#define TPM_ORD_GetCapabilitySigned 0x00000064 +#define TPM_ORD_GetOrdinalAuditStatus 0x0000008C +#define TPM_ORD_GetPubKey 0x00000021 +#define TPM_ORD_GetRandom 0x00000046 +#define TPM_ORD_GetTestResult 0x00000054 +#define TPM_ORD_GetTicks 0x000000F1 +#define TPM_ORD_IncrementCounter 0x000000DD +#define TPM_ORD_Init 0x00000097 +#define TPM_ORD_KeyControlOwner 0x00000023 +#define TPM_ORD_KillMaintenanceFeature 0x0000002E +#define TPM_ORD_LoadAuthContext 0x000000B7 +#define TPM_ORD_LoadContext 0x000000B9 +#define TPM_ORD_LoadKey 0x00000020 +#define TPM_ORD_LoadKey2 0x00000041 +#define TPM_ORD_LoadKeyContext 0x000000B5 +#define TPM_ORD_LoadMaintenanceArchive 0x0000002D +#define TPM_ORD_LoadManuMaintPub 0x0000002F +#define TPM_ORD_MakeIdentity 0x00000079 +#define TPM_ORD_MigrateKey 0x00000025 +#define TPM_ORD_NV_DefineSpace 0x000000CC +#define TPM_ORD_NV_ReadValue 0x000000CF +#define TPM_ORD_NV_ReadValueAuth 0x000000D0 +#define TPM_ORD_NV_WriteValue 0x000000CD +#define TPM_ORD_NV_WriteValueAuth 0x000000CE +#define TPM_ORD_OIAP 0x0000000A +#define TPM_ORD_OSAP 0x0000000B +#define TPM_ORD_OwnerClear 0x0000005B +#define TPM_ORD_OwnerReadInternalPub 0x00000081 +#define TPM_ORD_OwnerReadPubek 0x0000007D +#define TPM_ORD_OwnerSetDisable 0x0000006E +#define TPM_ORD_PCR_Reset 0x000000C8 +#define TPM_ORD_PcrRead 0x00000015 +#define TPM_ORD_PhysicalDisable 0x00000070 +#define TPM_ORD_PhysicalEnable 0x0000006F +#define TPM_ORD_PhysicalSetDeactivated 0x00000072 +#define TPM_ORD_Quote 0x00000016 +#define TPM_ORD_Quote2 0x0000003E +#define TPM_ORD_ReadCounter 0x000000DE +#define TPM_ORD_ReadManuMaintPub 0x00000030 +#define TPM_ORD_ReadPubek 0x0000007C +#define TPM_ORD_ReleaseCounter 0x000000DF +#define TPM_ORD_ReleaseCounterOwner 0x000000E0 +#define TPM_ORD_ReleaseTransportSigned 0x000000E8 +#define TPM_ORD_Reset 0x0000005A +#define TPM_ORD_ResetLockValue 0x00000040 +#define TPM_ORD_RevokeTrust 0x00000080 +#define TPM_ORD_SaveAuthContext 0x000000B6 +#define TPM_ORD_SaveContext 0x000000B8 +#define TPM_ORD_SaveKeyContext 0x000000B4 +#define TPM_ORD_SaveState 0x00000098 +#define TPM_ORD_Seal 0x00000017 +#define TPM_ORD_Sealx 0x0000003D +#define TPM_ORD_SelfTestFull 0x00000050 +#define TPM_ORD_SetCapability 0x0000003F +#define TPM_ORD_SetOperatorAuth 0x00000074 +#define TPM_ORD_SetOrdinalAuditStatus 0x0000008D +#define TPM_ORD_SetOwnerInstall 0x00000071 +#define TPM_ORD_SetOwnerPointer 0x00000075 +#define TPM_ORD_SetRedirection 0x0000009A +#define TPM_ORD_SetTempDeactivated 0x00000073 +#define TPM_ORD_SHA1Complete 0x000000A2 +#define TPM_ORD_SHA1CompleteExtend 0x000000A3 +#define TPM_ORD_SHA1Start 0x000000A0 +#define TPM_ORD_SHA1Update 0x000000A1 +#define TPM_ORD_Sign 0x0000003C +#define TPM_ORD_Startup 0x00000099 +#define TPM_ORD_StirRandom 0x00000047 +#define TPM_ORD_TakeOwnership 0x0000000D +#define TPM_ORD_Terminate_Handle 0x00000096 +#define TPM_ORD_TickStampBlob 0x000000F2 +#define TPM_ORD_UnBind 0x0000001E +#define TPM_ORD_Unseal 0x00000018 + +#define TSC_ORD_PhysicalPresence 0x4000000A +#define TSC_ORD_ResetEstablishmentBit 0x4000000B + +/* 19. NV storage structures */ + +/* 19.1 TPM_NV_INDEX rev 110 + + The index provides the handle to identify the area of storage. The reserved bits allow for a + segregation of the index name space to avoid name collisions. + + The TPM may check the resvd bits for zero. Thus, applications should set the bits to zero. + + The TCG defines the space where the high order bits (T, P, U) are 0. The other spaces are + controlled by the indicated entity. + + T is the TPM manufacturer reserved bit. 0 indicates a TCG defined value. 1 indicates a TPM + manufacturer specific value. + + P is the platform manufacturer reserved bit. 0 indicates a TCG defined value. 1 indicates that + the index is controlled by the platform manufacturer. + + U is for the platform user. 0 indicates a TCG defined value. 1 indicates that the index is + controlled by the platform user. + + The TPM_NV_INDEX is a 32-bit value. + 3 2 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |T|P|U|D| resvd | Purview | Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Where: + + 1. The TPM MAY return an error if the reserved area bits are not set to 0. + + 2. The TPM MUST accept all values for T, P, and U + + 3. D indicates defined. 1 indicates that the index is permanently defined and that any + TPM_NV_DefineSpace operation will fail after nvLocked is set TRUE. + + a. TCG reserved areas MAY have D set to 0 or 1 + + 4. Purview is the value used to indicate the platform specific area. This value is the + same as used for command ordinals. + + a. The TPM MUST reject purview values that the TPM cannot support. This means that an + index value for a PDA MUST be rejected by a TPM designed to work only on the PC Client. +*/ + +#define TPM_NV_INDEX_T_BIT 0x80000000 +#define TPM_NV_INDEX_P_BIT 0x40000000 +#define TPM_NV_INDEX_U_BIT 0x20000000 +#define TPM_NV_INDEX_D_BIT 0x10000000 +/* added kgold */ +#define TPM_NV_INDEX_RESVD 0x0f000000 +#define TPM_NV_INDEX_PURVIEW_BIT 16 +#define TPM_NV_INDEX_PURVIEW_MASK 0x00ff0000 + +/* 19.1.1 Required TPM_NV_INDEX values rev 97 + + The required index values must be found on each TPM regardless of platform. These areas are + always present and do not require a TPM_DefineSpace command to allocate. + + A platform specific specification may add additional required index values for the platform. + + The TPM MUST reserve the space as indicated for the required index values +*/ + +#define TPM_NV_INDEX_LOCK 0xFFFFFFFF /* This value turns on the NV authorization + protections. Once executed all NV areas use the + protections as defined. This value never resets. + + Attempting to execute TPM_NV_DefineSpace on this value + with non-zero size MAY result in a TPM_BADINDEX + response. + */ + +#define TPM_NV_INDEX0 0x00000000 /* This value allows for the setting of the bGlobalLock + flag, which is only reset on TPM_Startup(ST_Clear) + + Attempting to execute TPM_NV_WriteValue with a size other + than zero MAY result in the TPM_BADINDEX error code. + */ + +#define TPM_NV_INDEX_DIR 0x10000001 /* Size MUST be 20. This index points to the deprecated DIR + command area from 1.1. The TPM MUST map this reserved + space to be the area operated on by the 1.1 DIR commands. + */ + +/* 19.1.2 Reserved Index values rev 116 + + The reserved values are defined to avoid index collisions. These values are not in each and every + TPM. + + 1. The reserved index values are to avoid index value collisions. + 2. These index values require a TPM_DefineSpace to have the area for the index allocated + 3. A platform specific specification MAY indicate that reserved values are required. + 4. The reserved index values MAY have their D bit set by the TPM vendor to permanently +*/ + +#define TPM_NV_INDEX_TPM 0x0000Fxxx /* Reserved for TPM use */ +#define TPM_NV_INDEX_EKCert 0x0000F000 /* The Endorsement credential */ + +#define TPM_NV_INDEX_TPM_CC 0x0000F001 /* The TPM Conformance credential */ +#define TPM_NV_INDEX_PlatformCert 0x0000F002 /* The platform credential */ +#define TPM_NV_INDEX_Platform_CC 0x0000F003 /* The Platform conformance credential */ +#define TPM_NV_INDEX_TRIAL 0x0000F004 /* To try TPM_NV_DefineSpace without + actually allocating NV space */ + +#if 0 +#define TPM_NV_INDEX_PC 0x0001xxxx /* Reserved for PC Client use */ +#define TPM_NV_INDEX_GPIO_xx 0x000116xx /* Reserved for GPIO pins */ +#define TPM_NV_INDEX_PDA 0x0002xxxx /* Reserved for PDA use */ +#define TPM_NV_INDEX_MOBILE 0x0003xxxx /* Reserved for mobile use */ +#define TPM_NV_INDEX_SERVER 0x0004xxxx /* Reserved for Server use */ +#define TPM_NV_INDEX_PERIPHERAL 0x0005xxxx /* Reserved for peripheral use */ +#define TPM_NV_INDEX_TSS 0x0006xxxx /* Reserved for TSS use */ +#define TPM_NV_INDEX_GROUP_RESV 0x00xxxxxx /* Reserved for TCG WG use */ +#endif + +#define TPM_NV_INDEX_GPIO_00 0x00011600 /* GPIO-Express-00 */ + +#define TPM_NV_INDEX_GPIO_START 0x00011600 /* Reserved for GPIO pins */ +#define TPM_NV_INDEX_GPIO_END 0x000116ff /* Reserved for GPIO pins */ + +/* 19.2 TPM_NV_ATTRIBUTES rev 99 + + The attributes TPM_NV_PER_AUTHREAD and TPM_NV_PER_OWNERREAD cannot both be set to TRUE. + Similarly, the attributes TPM_NV_PER_AUTHWRITE and TPM_NV_PER_OWNERWRITE cannot both be set to + TRUE. +*/ + +#define TPM_NV_PER_READ_STCLEAR 0x80000000 /* 31: The value can be read until locked by a + read with a data size of 0. It can only be + unlocked by TPM_Startup(ST_Clear) or a + successful write. Lock held for each area in + bReadSTClear. */ +/* #define 30:19 Reserved */ +#define TPM_NV_PER_AUTHREAD 0x00040000 /* 18: The value requires authorization to read + */ +#define TPM_NV_PER_OWNERREAD 0x00020000 /* 17: The value requires TPM Owner authorization + to read. */ +#define TPM_NV_PER_PPREAD 0x00010000 /* 16: The value requires physical presence to + read */ +#define TPM_NV_PER_GLOBALLOCK 0x00008000 /* 15: The value is writable until a write to + index 0 is successful. The lock of this + attribute is reset by + TPM_Startup(ST_CLEAR). Lock held by SF -> + bGlobalLock */ +#define TPM_NV_PER_WRITE_STCLEAR 0x00004000 /* 14: The value is writable until a write to + the specified index with a datasize of 0 is + successful. The lock of this attribute is + reset by TPM_Startup(ST_CLEAR). Lock held for + each area in bWriteSTClear. */ +#define TPM_NV_PER_WRITEDEFINE 0x00002000 /* 13: Lock set by writing to the index with a + datasize of 0. Lock held for each area in + bWriteDefine. This is a persistent lock. */ +#define TPM_NV_PER_WRITEALL 0x00001000 /* 12: The value must be written in a single + operation */ +/* #define 11:3 Reserved for write additions */ +#define TPM_NV_PER_AUTHWRITE 0x00000004 /* 2: The value requires authorization to write + */ +#define TPM_NV_PER_OWNERWRITE 0x00000002 /* 1: The value requires TPM Owner authorization + to write */ +#define TPM_NV_PER_PPWRITE 0x00000001 /* 0: The value requires physical presence to + write */ + +/* 20.2.1 Owner Permission Settings rev 87 */ + +/* Per1 bits */ + +#define TPM_DELEGATE_PER1_MASK 0xffffffff /* mask of legal bits */ +#define TPM_DELEGATE_KeyControlOwner 31 +#define TPM_DELEGATE_SetOrdinalAuditStatus 30 +#define TPM_DELEGATE_DirWriteAuth 29 +#define TPM_DELEGATE_CMK_ApproveMA 28 +#define TPM_DELEGATE_NV_WriteValue 27 +#define TPM_DELEGATE_CMK_CreateTicket 26 +#define TPM_DELEGATE_NV_ReadValue 25 +#define TPM_DELEGATE_Delegate_LoadOwnerDelegation 24 +#define TPM_DELEGATE_DAA_Join 23 +#define TPM_DELEGATE_AuthorizeMigrationKey 22 +#define TPM_DELEGATE_CreateMaintenanceArchive 21 +#define TPM_DELEGATE_LoadMaintenanceArchive 20 +#define TPM_DELEGATE_KillMaintenanceFeature 19 +#define TPM_DELEGATE_OwnerReadInternalPub 18 +#define TPM_DELEGATE_ResetLockValue 17 +#define TPM_DELEGATE_OwnerClear 16 +#define TPM_DELEGATE_DisableOwnerClear 15 +#define TPM_DELEGATE_NV_DefineSpace 14 +#define TPM_DELEGATE_OwnerSetDisable 13 +#define TPM_DELEGATE_SetCapability 12 +#define TPM_DELEGATE_MakeIdentity 11 +#define TPM_DELEGATE_ActivateIdentity 10 +#define TPM_DELEGATE_OwnerReadPubek 9 +#define TPM_DELEGATE_DisablePubekRead 8 +#define TPM_DELEGATE_SetRedirection 7 +#define TPM_DELEGATE_FieldUpgrade 6 +#define TPM_DELEGATE_Delegate_UpdateVerification 5 +#define TPM_DELEGATE_CreateCounter 4 +#define TPM_DELEGATE_ReleaseCounterOwner 3 +#define TPM_DELEGATE_Delegate_Manage 2 +#define TPM_DELEGATE_Delegate_CreateOwnerDelegation 1 +#define TPM_DELEGATE_DAA_Sign 0 + +/* Per2 bits */ +#define TPM_DELEGATE_PER2_MASK 0x00000000 /* mask of legal bits */ +/* All reserved */ + +/* 20.2.3 Key Permission settings rev 85 */ + +/* Per1 bits */ + +#define TPM_KEY_DELEGATE_PER1_MASK 0x1fffffff /* mask of legal bits */ +#define TPM_KEY_DELEGATE_CMK_ConvertMigration 28 +#define TPM_KEY_DELEGATE_TickStampBlob 27 +#define TPM_KEY_DELEGATE_ChangeAuthAsymStart 26 +#define TPM_KEY_DELEGATE_ChangeAuthAsymFinish 25 +#define TPM_KEY_DELEGATE_CMK_CreateKey 24 +#define TPM_KEY_DELEGATE_MigrateKey 23 +#define TPM_KEY_DELEGATE_LoadKey2 22 +#define TPM_KEY_DELEGATE_EstablishTransport 21 +#define TPM_KEY_DELEGATE_ReleaseTransportSigned 20 +#define TPM_KEY_DELEGATE_Quote2 19 +#define TPM_KEY_DELEGATE_Sealx 18 +#define TPM_KEY_DELEGATE_MakeIdentity 17 +#define TPM_KEY_DELEGATE_ActivateIdentity 16 +#define TPM_KEY_DELEGATE_GetAuditDigestSigned 15 +#define TPM_KEY_DELEGATE_Sign 14 +#define TPM_KEY_DELEGATE_CertifyKey2 13 +#define TPM_KEY_DELEGATE_CertifyKey 12 +#define TPM_KEY_DELEGATE_CreateWrapKey 11 +#define TPM_KEY_DELEGATE_CMK_CreateBlob 10 +#define TPM_KEY_DELEGATE_CreateMigrationBlob 9 +#define TPM_KEY_DELEGATE_ConvertMigrationBlob 8 +#define TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation 7 +#define TPM_KEY_DELEGATE_ChangeAuth 6 +#define TPM_KEY_DELEGATE_GetPubKey 5 +#define TPM_KEY_DELEGATE_UnBind 4 +#define TPM_KEY_DELEGATE_Quote 3 +#define TPM_KEY_DELEGATE_Unseal 2 +#define TPM_KEY_DELEGATE_Seal 1 +#define TPM_KEY_DELEGATE_LoadKey 0 + +/* Per2 bits */ +#define TPM_KEY_DELEGATE_PER2_MASK 0x00000000 /* mask of legal bits */ +/* All reserved */ + +/* 20.3 TPM_FAMILY_FLAGS rev 87 + + These flags indicate the operational state of the delegation and family table. These flags + are additions to TPM_PERMANENT_FLAGS and are not stand alone values. +*/ + +#define TPM_DELEGATE_ADMIN_LOCK 0x00000002 /* TRUE: Some TPM_Delegate_XXX commands are locked and + return TPM_DELEGATE_LOCK + + FALSE: TPM_Delegate_XXX commands are available + + Default is FALSE */ +#define TPM_FAMFLAG_ENABLED 0x00000001 /* When TRUE the table is enabled. The default value is + FALSE. */ + +/* 20.14 TPM_FAMILY_OPERATION Values rev 87 + + These are the opFlag values used by TPM_Delegate_Manage. +*/ + +#define TPM_FAMILY_CREATE 0x00000001 /* Create a new family */ +#define TPM_FAMILY_ENABLE 0x00000002 /* Set or reset the enable flag for this family. */ +#define TPM_FAMILY_ADMIN 0x00000003 /* Prevent administration of this family. */ +#define TPM_FAMILY_INVALIDATE 0x00000004 /* Invalidate a specific family row. */ + +/* 21.9 TPM_DA_STATE rev 100 + + TPM_DA_STATE enumerates the possible states of the dictionary attack mitigation logic. +*/ + +#define TPM_DA_STATE_INACTIVE 0x00 /* The dictionary attack mitigation logic is currently + inactive */ +#define TPM_DA_STATE_ACTIVE 0x01 /* The dictionary attack mitigation logic is + active. TPM_DA_ACTION_TYPE (21.10) is in progress. */ + +/* 21.10 TPM_DA_ACTION_TYPE rev 100 + */ + +/* 31-4 Reserved No information and MUST be FALSE */ + +#define TPM_DA_ACTION_FAILURE_MODE 0x00000008 /* bit 3: The TPM is in failure mode. */ +#define TPM_DA_ACTION_DEACTIVATE 0x00000004 /* bit 2: The TPM is in the deactivated state. */ +#define TPM_DA_ACTION_DISABLE 0x00000002 /* bit 1: The TPM is in the disabled state. */ +#define TPM_DA_ACTION_TIMEOUT 0x00000001 /* bit 0: The TPM will be in a locked state for + TPM_DA_INFO -> actionDependValue seconds. This + value is dynamic, depending on the time the + lock has been active. */ + +/* 22. DAA Structures rev 91 + + All byte and bit areas are byte arrays treated as large integers +*/ + +#define DAA_SIZE_r0 43 +#define DAA_SIZE_r1 43 +#define DAA_SIZE_r2 128 +#define DAA_SIZE_r3 168 +#define DAA_SIZE_r4 219 +#define DAA_SIZE_NT 20 +#define DAA_SIZE_v0 128 +#define DAA_SIZE_v1 192 +#define DAA_SIZE_NE 256 +#define DAA_SIZE_w 256 +#define DAA_SIZE_issuerModulus 256 + +/* check that DAA_SIZE_issuerModulus will fit in DAA_scratch */ +#if (DAA_SIZE_issuerModulus != 256) +#error "DAA_SIZE_issuerModulus must be 256" +#endif + +/* 22.2 Constant definitions rev 91 */ + +#define DAA_power0 104 +#define DAA_power1 1024 + +#endif diff --git a/src/tpm12/tpm_counter.c b/src/tpm12/tpm_counter.c new file mode 100644 index 0000000..65a2db2 --- /dev/null +++ b/src/tpm12/tpm_counter.c @@ -0,0 +1,1565 @@ +/********************************************************************************/ +/* */ +/* Counter Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_counter.c 4539 2011-04-04 21:44:22Z kgoldman $ */ +/* */ +//* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" + +#include "tpm_counter.h" + +/* + Monotonic Counter Resource Handling +*/ + +/* TPM_Counters_Init() initializes the monotonic counters + */ + +void TPM_Counters_Init(TPM_COUNTER_VALUE *monotonicCounters) +{ + uint32_t i; + + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + TPM_CounterValue_Init(&(monotonicCounters[i])); + } + return; +} + +/* TPM_Counters_Load() loads the monotonic counters + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_Counters_Load(TPM_COUNTER_VALUE *monotonicCounters, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + + /* load the counters */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + rc = TPM_CounterValue_Load(&(monotonicCounters[i]), stream, stream_size); + } + return rc; +} + +TPM_RESULT TPM_Counters_Store(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + uint32_t i; + + /* store the counters */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + rc = TPM_CounterValue_Store(sbuffer, &(monotonicCounters[i])); + } + return rc; +} + +/* TPM_Counters_StoreHandles() stores a count of the created counters and a list of created counter + handles. +*/ + +TPM_RESULT TPM_Counters_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + uint16_t loaded; + uint32_t i; + + printf(" TPM_Counters_StoreHandles:\n"); + if (rc == 0) { + loaded = 0; + /* count the number of loaded counters */ + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if ((monotonicCounters[i]).valid) { + loaded++; + } + } + /* store created handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loaded); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + if ((monotonicCounters[i]).valid) { + /* the handle is just the index */ + rc = TPM_Sbuffer_Append32(sbuffer, i); /* store it */ + } + } + return rc; +} + +/* TPM_Counters_GetSpace() returns the number of unused monotonicCounters. + */ + +void TPM_Counters_GetSpace(uint32_t *space, + TPM_COUNTER_VALUE *monotonicCounters) +{ + uint32_t i; + + printf(" TPM_Counters_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if (!(monotonicCounters[i]).valid) { + (*space)++; + } + } + return; +} + + +/* TPM_Counters_GetNewHandle() checks for space in the monotonicCounters table. + + If there is space, it returns a TPM_COUNTER_VALUE entry in 'tpm_counter_value' and its + handle in 'countID'. The entry is marked 'valid'. + + Returns TPM_RESOURCES if there is no space in the sessions table. monotonicCounters is not + altered on error. +*/ + +TPM_RESULT TPM_Counters_GetNewHandle(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNT_ID *countID, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + TPM_BOOL is_space; + + printf(" TPM_Counters_GetNewHandle:\n"); + for (*countID = 0, is_space = FALSE ; + *countID < TPM_MIN_COUNTERS ; + (*countID)++) { + + if (!(monotonicCounters[*countID]).valid) { + is_space = TRUE; + break; + } + } + /* NOTE: According to TPMWG email, TPM_COUNT_ID can be an index */ + if (is_space) { + printf(" TPM_Counters_GetNewHandle: Assigned handle %u\n", *countID); + *tpm_counter_value = &(monotonicCounters[*countID]); + (*tpm_counter_value)->valid = TRUE; /* mark it occupied */ + } + else { + printf("TPM_Counters_GetNewHandle: Error, no space in monotonicCounters table\n"); + rc = TPM_RESOURCES; + } + return rc; +} + +/* TPM_Counters_GetNextCount() searches the monotonicCounters for the maximum count, and returns + nextCount equal to the incremented maximum count. + + The counter does not have to be valid (created). It can be invalid (released). +*/ + +void TPM_Counters_GetNextCount(TPM_ACTUAL_COUNT *nextCount, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_COUNT_ID countID; + TPM_ACTUAL_COUNT maxCount = 0; + + printf(" TPM_Counters_GetNextCount:\n"); + for (countID = 0 ; countID < TPM_MIN_COUNTERS ; countID++) { + if (monotonicCounters[countID].counter > maxCount) { + maxCount = monotonicCounters[countID].counter; + } + } + *nextCount = maxCount + 1; + printf(" TPM_Counters_GetNextCount: Next count %u\n", *nextCount); + return; +} + +/* TPM_Counters_IsValidId() verifies that countID is in range and a created counter + */ + +TPM_RESULT TPM_Counters_IsValidId(TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Counters_IsValidId: countID %u\n", countID); + /* range check */ + if (rc == 0) { + if (countID >= TPM_MIN_COUNTERS) { + printf("TPM_Counters_IsValidId: Error countID %u out of range\n", countID); + rc = TPM_BAD_COUNTER ; + } + } + /* validity (creation) check */ + if (rc == 0) { + if (!(monotonicCounters[countID].valid)) { + printf("TPM_Counters_IsValidId: Error countID %u invalid\n", countID); + rc = TPM_BAD_COUNTER ; + } + } + return rc; +} + + +/* TPM_Counters_GetCounterValue() gets the TPM_COUNTER_VALUE associated with the countID. + + */ + +TPM_RESULT TPM_Counters_GetCounterValue(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Counters_GetCounterValue: countID %u\n", countID); + /* valid counter check */ + if (rc == 0) { + rc = TPM_Counters_IsValidId(monotonicCounters, countID); + } + if (rc == 0) { + *tpm_counter_value = &(monotonicCounters[countID]); + } + return rc; +} + +/* TPM_Counters_Release() iterates through all monotonicCounter's, and releases those that are + created. + + The resource is set invalid, and the authorization data and digest are cleared. + + a. This includes invalidating all currently allocated counters. The result will be no + currently allocated counters and the new owner will need to allocate counters. The actual + count value will continue to increase. +*/ + +TPM_RESULT TPM_Counters_Release(TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + TPM_COUNT_ID i; + + printf(" TPM_Counters_Release:\n"); + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if (monotonicCounters[i].valid) { + /* the actual count value does not reset to zero */ + printf(" TPM_Counters_Release: Releasing %u\n", i); + TPM_Secret_Init(monotonicCounters[i].authData); + TPM_Digest_Init(monotonicCounters[i].digest); + monotonicCounters[i].valid = FALSE; + } + } + return rc; +} + +/* TPM_Counters_GetActiveCounter() gets the active counter based on the value in TPM_STCLEAR_DATA -> + countID */ + +void TPM_Counters_GetActiveCounter(TPM_COUNT_ID *activeCounter, + TPM_COUNT_ID countID) +{ + if (countID < TPM_MIN_COUNTERS) { + *activeCounter = countID; + } + else { + *activeCounter = TPM_COUNT_ID_NULL; + } +} + +/* + TPM_COUNTER_VALUE +*/ + +/* TPM_CounterValue_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CounterValue_Init(TPM_COUNTER_VALUE *tpm_counter_value) +{ + printf(" TPM_CounterValue_Init:\n"); + memset(tpm_counter_value->label, 0, TPM_COUNTER_LABEL_SIZE); + tpm_counter_value->counter = 0; + TPM_Secret_Init(tpm_counter_value->authData); + tpm_counter_value->valid = FALSE; + return; +} + +/* TPM_CounterValue_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_CounterValue_Load(TPM_COUNTER_VALUE *tpm_counter_value, /* result */ + unsigned char **stream, /* pointer to next + parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_COUNTER_VALUE, stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE, stream, stream_size); + } + /* load counter */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_counter_value->counter), stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_counter_value->authData, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_counter_value->valid), stream, stream_size); + } + return rc; +} + +/* TPM_CounterValue_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + It is typically used to store the structure in the permanent data file. +*/ + +TPM_RESULT TPM_CounterValue_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Store:\n"); + /* store tag, label, counter */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, tpm_counter_value); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_counter_value->authData); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_counter_value->valid), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_CounterValue_StorePublic() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This version only stores the public, externally visible fields: tag, label, counter. It is + typically used to return outgoing parameters. +*/ + +TPM_RESULT TPM_CounterValue_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_StorePublic:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_COUNTER_VALUE); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); + } + /* store counter */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_counter_value->counter); + } + return rc; +} + +/* TPM_CounterValue_CopyPublic() copies the public, externally visible fields: tag, label, counter. + */ + +void TPM_CounterValue_CopyPublic(TPM_COUNTER_VALUE *dst_tpm_counter_value, + TPM_COUNTER_VALUE *src_tpm_counter_value) +{ + memcpy(dst_tpm_counter_value->label, src_tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); + dst_tpm_counter_value->counter = src_tpm_counter_value->counter; + return; +} + +/* TPM_CounterValue_Set() + + Sets the label, counter, and authData members from input parameters, and sets the digest from + members. +*/ + +TPM_RESULT TPM_CounterValue_Set(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID, + BYTE *label, + TPM_ACTUAL_COUNT counter, + TPM_SECRET authData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Set:\n"); + tpm_counter_value->counter = counter; + memcpy(tpm_counter_value->label, label, TPM_COUNTER_LABEL_SIZE); + TPM_Secret_Copy(tpm_counter_value->authData, authData); + /* create a hopefully unique digest of the object for the OSAP setup. The cast is OK here since + the actual value of the digest is never verified. */ + rc = TPM_SHA1(tpm_counter_value->digest, + sizeof(TPM_COUNT_ID), (unsigned char *)&countID, + TPM_COUNTER_LABEL_SIZE, label, + TPM_SECRET_SIZE, authData, + 0, NULL); + return rc; + +} + +/* TPM_CounterValue_Release() releases a counter. + + The resource is set invalid, and the authorization data and digest are cleared. +*/ + +TPM_RESULT TPM_CounterValue_Release(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Release: countID %u\n", countID); + /* sanity check */ + if (rc == 0) { + if (!tpm_counter_value->valid) { + printf("TPM_CounterValue_Release: Error (fatal), countID %u not valid\n", countID); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + TPM_Secret_Init(tpm_counter_value->authData); + TPM_Digest_Init(tpm_counter_value->digest); + tpm_counter_value->valid = FALSE; + } + return rc; +} + +/* + Processing Functions +*/ + +/* 25.1 TPM_CreateCounter rev 98 + + This command creates the counter but does not select the counter. Counter creation assigns an + AuthData value to the counter and sets the counters original start value. The original start value + is the current internal base value plus one. Setting the new counter to the internal base avoids + attacks on the system that are attempting to use old counter values. + + This command creates a new monotonic counter. The TPM MUST support a minimum of 4 concurrent + counters. +*/ + +TPM_RESULT TPM_Process_CreateCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENCAUTH encAuth; /* The encrypted auth data for the new counter */ + BYTE label[TPM_COUNTER_LABEL_SIZE]; /* Label to associate with counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* Authorization ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET a1Auth; + TPM_ACTUAL_COUNT nextCount; + TPM_BOOL writeAllNV= FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_COUNT_ID countID = 0; /* The handle for the counter */ + TPM_COUNTER_VALUE *counterValue = NULL; /* The starting counter value */ + + printf("TPM_Process_CreateCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get authData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get label */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Loadn(label, TPM_COUNTER_LABEL_SIZE, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateCounter: label", label); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Using the authHandle field, validate the owner's AuthData to execute the command and all + of the incoming parameters. The authorization session MUST be OSAP or DSAP. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Ignore continueAuthSession on input and set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 3. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 4. Validate that there is sufficient internal space in the TPM to create a new counter. If + there is insufficient space the command returns an error. */ + /* a. The TPM MUST provide storage for a1, TPM_COUNTER_VALUE, countID, and any other internal + data the TPM needs to associate with the counter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetNewHandle(&counterValue, /* structure */ + &countID, /* index */ + tpm_state->tpm_permanent_data.monotonicCounter); + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + /* 5. Increment the max counter value */ + TPM_Counters_GetNextCount(&nextCount, + tpm_state->tpm_permanent_data.monotonicCounter); + /* 6. Set the counter to the max counter value */ + /* 7. Set the counter label to label */ + returnCode = TPM_CounterValue_Set(counterValue, + countID, + label, + nextCount, + a1Auth); + /* 8. Create a countID */ + /* NOTE Done in TPM_Counters_GetNewHandle() */ + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the countID */ + returnCode = TPM_Sbuffer_Append32(response, countID); + } + if (returnCode == TPM_SUCCESS) { + /* Return the TPM_COUNTER_VALUE publicly visible members */ + returnCode = TPM_CounterValue_StorePublic(response, counterValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.2 TPM_IncrementCounter rev 87 + + This authorized command increments the indicated counter by one. Once a counter has been + incremented then all subsequent increments must be for the same handle until a successful + TPM_Startup(ST_CLEAR) is executed. + + The order for checking validation of the command parameters when no counter is active, keeps an + attacker from creating a denial-of-service attack. + + This function increments the counter by 1. + The TPM MAY implement increment throttling to avoid burn problems +*/ + +TPM_RESULT TPM_Process_IncrementCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* The handle of a valid counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for counter + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use + of countID. HMAC key: countID -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_COUNTER_VALUE *counterValue = NULL; /* The counter value */ + + printf("TPM_Process_IncrementCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_IncrementCounter: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + counterAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_IncrementCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* The first check is that either there is no active counter and the countID has been created + or that the countID is the active counter */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { + /* a. Validate that countID is a valid counter, return TPM_BAD_COUNTER on mismatch */ + returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* 2. else (TPM_STCLEAR_DATA -> countID is not NULL */ + else { + /* a. If TPM_STCLEAR_DATA -> countID does not equal countID */ + if (tpm_state->tpm_stclear_data.countID != countID) { + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_ILLEGAL) { + printf("TPM_Process_IncrementCounter: Error, counter has been released\n"); + } + else { + printf("TPM_Process_IncrementCounter: Error, %u is already active\n", + tpm_state->tpm_stclear_data.countID); + } + /* i. Return TPM_BAD_COUNTER */ + returnCode = TPM_BAD_COUNTER; + } + } + } + /* b. Validate the command parameters using counterAuth */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_COUNTER, + ordinal, + NULL, + &(counterValue->authData), /* OIAP */ + counterValue->digest); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + counterAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { + /* c. Set TPM_STCLEAR_DATA -> countID to countID */ + tpm_state->tpm_stclear_data.countID = countID; + printf("TPM_Process_IncrementCounter: Setting %u as active counter\n", countID); + } + } + if (returnCode == TPM_SUCCESS) { + /* 3. Increments the counter by 1 */ + counterValue->counter++; /* in TPM_PERMANENT_DATA */ + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_IncrementCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 4. Return new count value in count */ + returnCode = TPM_CounterValue_StorePublic(response, counterValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.3 TPM_ReadCounter rev 87 + + Reading the counter provides the caller with the current number in the sequence. + + This returns the current value for the counter indicated. The counter MAY be any valid counter. +*/ + +TPM_RESULT TPM_Process_ReadCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* ID value of the counter */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReadCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that countID points to a valid counter. Return TPM_BAD_COUNTER on error. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReadCounter: countID %u\n", countID); + returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Return count (directly from TPM_PERMANENT_DATA) */ + returnCode = TPM_CounterValue_StorePublic + (response, &(tpm_state->tpm_permanent_data.monotonicCounter[countID])); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 25.4 TPM_ReleaseCounter rev 87 + + This command releases a counter such that no reads or increments of the indicated counter will + succeed. + + The TPM uses countID to locate a valid counter. +*/ + +TPM_RESULT TPM_Process_ReleaseCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* ID value of the counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for countID + authorization */ + TPM_NONCE nonceOdd; /* Nonce associated with countID */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use + of countID. HMAC key: countID -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_COUNTER_VALUE *counterValue; /* associated with countID */ + TPM_SECRET savedAuth; /* saved copy for response */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV*/ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReleaseCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounter: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + counterAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Authenticate the command and the parameters using the AuthData pointed to by + countID. Return TPM_AUTHFAIL on error */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_COUNTER, + ordinal, + NULL, + &(counterValue->authData), /* OIAP */ + counterValue->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it gets invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + /* Validate the authorization to use the key pointed to by countID */ + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + counterAuth); /* Authorization digest for input */ + } + /* 3. The TPM invalidates sessions */ + /* a. MUST invalidate all OSAP sessions associated with the counter */ + /* b. MAY invalidate any other session */ + /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ + &(counterValue->digest)); /* entityDigest */ + } + /* 2. The TPM invalidates all internal information regarding the counter. This includes + releasing countID such that any subsequent attempts to use countID will fail. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounter: Releasing counter %u\n", countID); + returnCode = TPM_CounterValue_Release(counterValue, countID); + } + if (returnCode == TPM_SUCCESS) { + writeAllNV= TRUE; + /* 4. If TPM_STCLEAR_DATA -> countID equals countID, */ + if (tpm_state->tpm_stclear_data.countID == countID ) { + printf("TPM_Process_ReleaseCounter: Deactivating counter %u\n", countID); + /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the NULL value) */ + tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; + } + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved countID HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.5 TPM_ReleaseCounterOwner rev 101 + + This command releases a counter such that no reads or increments of the indicated counter will + succeed. + + This invalidates all information regarding a counter. +*/ + +TPM_RESULT TPM_Process_ReleaseCounterOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + TPM_COUNT_ID countID; /* ID value of the counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest that authorizes the + inputs. HMAC key: ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = TRUE; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_COUNTER_VALUE *counterValue; /* associated with countID */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReleaseCounterOwner: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounterOwner: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseCounterOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that ownerAuth properly authorizes the command and parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM uses countID to locate a valid counter. Return TPM_BAD_COUNTER if not found. */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ + &(counterValue->digest)); /* entityDigest */ + } + /* 3. The TPM invalidates all internal information regarding the counter. This includes + releasing countID such that any subsequent attempts to use countID will fail. */ + /* NOTE: This function can only return a TPM_FAIL error, so that the failure to store + TPM_PERMANENT_DATA will already be reported as fatal. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CounterValue_Release(counterValue, countID); + } + /* 4. The TPM invalidates sessions */ + /* a. MUST invalidate all OSAP sessions associated with the counter */ + /* b. MAY invalidate any other session */ + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + /* 5. If TPM_STCLEAR_DATA -> countID equals countID, */ + if (tpm_state->tpm_stclear_data.countID == countID ) { + printf("TPM_Process_ReleaseCounterOwner: Deactivating counter %u\n", countID); + /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the zero value) */ + tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; + } + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseCounterOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm12/tpm_counter.h b/src/tpm12/tpm_counter.h new file mode 100644 index 0000000..18709d2 --- /dev/null +++ b/src/tpm12/tpm_counter.h @@ -0,0 +1,140 @@ +/********************************************************************************/ +/* */ +/* Counter Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_counter.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_COUNTER_H +#define TPM_COUNTER_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* + Counter Resource Handling +*/ + +void TPM_Counters_Init(TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_Load(TPM_COUNTER_VALUE *monotonicCountersa, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Counters_Store(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters); + +TPM_RESULT TPM_Counters_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_GetNewHandle(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNT_ID *countID, + TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetSpace(uint32_t *space, + TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetNextCount(TPM_ACTUAL_COUNT *nextCount, + TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_IsValidId(TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID); +TPM_RESULT TPM_Counters_GetCounterValue(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID); +TPM_RESULT TPM_Counters_Release(TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetActiveCounter(TPM_COUNT_ID *activeCounter, + TPM_COUNT_ID countID); + + +/* + TPM_COUNTER_VALUE +*/ + +void TPM_CounterValue_Init(TPM_COUNTER_VALUE *tpm_counter_value); +TPM_RESULT TPM_CounterValue_Load(TPM_COUNTER_VALUE *tpm_counter_value, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CounterValue_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value); + +TPM_RESULT TPM_CounterValue_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value); +void TPM_CounterValue_CopyPublic(TPM_COUNTER_VALUE *dst_tpm_counter_value, + TPM_COUNTER_VALUE *src_tpm_counter_value); +TPM_RESULT TPM_CounterValue_Set(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID, + BYTE *label, + TPM_ACTUAL_COUNT counter, + TPM_SECRET authData); +TPM_RESULT TPM_CounterValue_Release(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID); +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_CreateCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_IncrementCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReadCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReleaseCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReleaseCounterOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm12/tpm_crypto.c b/src/tpm12/tpm_crypto.c new file mode 100644 index 0000000..9fb4fce --- /dev/null +++ b/src/tpm12/tpm_crypto.c @@ -0,0 +1,3088 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto.c 4767 2017-07-27 23:06:32Z 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. */ +/********************************************************************************/ + +/* This is the openSSL implementation */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/crypto.h> +#include <openssl/rand.h> +#include <openssl/sha.h> +#include <openssl/engine.h> + +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_crypto.h" + +#include "tpm_openssl_helpers.h" // libtpms added + +/* The TPM OAEP encoding parameter */ +static const unsigned char tpm_oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + + +/* local prototypes */ + +static void TPM_OpenSSL_PrintError(void); + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSA **rsa_pub_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSA **rsa_pri_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSA *rsa_pri_key); +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSA *rsa_pri_key); + +static TPM_RESULT TPM_BN_CTX_new(BN_CTX **ctx); + + + +/* TPM_SYMMETRIC_KEY_DATA is a crypto library platform dependent symmetric key structure + */ +#ifdef TPM_DES + +/* local prototype and structure for DES */ + +#include <openssl/des.h> + +/* DES requires data lengths that are a multiple of the block size */ +#define TPM_DES_BLOCK_SIZE 8 + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + BYTE fill; + DES_cblock des_cblock1; + DES_cblock des_cblock2; + DES_cblock des_cblock3; +} TPM_SYMMETRIC_KEY_DATA; + +static TPM_RESULT TPM_SymmetricKeyData_Crypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t length, + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + int enc, + TPM_RESULT error); + +#endif + +#ifdef TPM_AES + +/* local prototype and structure for AES */ + +#include <openssl/aes.h> + +#if defined(__OpenBSD__) + # define OPENSSL_OLD_API +#else + #if OPENSSL_VERSION_NUMBER < 0x10100000 + #define OPENSSL_OLD_API + #endif +#endif + +/* AES requires data lengths that are a multiple of the block size */ +#define TPM_AES_BITS 128 +/* The AES block size is always 16 bytes */ +#define TPM_AES_BLOCK_SIZE 16 + +/* Since the AES key is often derived by truncating the session shared secret, test that it's not + too large +*/ + +#if (TPM_AES_BLOCK_SIZE > TPM_SECRET_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_SECRET_SIZE +#endif + +/* The AES initial CTR value is derived from a nonce. */ + +#if (TPM_AES_BLOCK_SIZE > TPM_NONCE_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_NONCE_SIZE +#endif + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + TPM_BOOL fill; + unsigned char userKey[TPM_AES_BLOCK_SIZE]; + /* For performance, generate these once from userKey */ + AES_KEY aes_enc_key; + AES_KEY aes_dec_key; +} TPM_SYMMETRIC_KEY_DATA; + +static TPM_RESULT TPM_SymmetricKeyData_SetKeys(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data); +static TPM_RESULT TPM_SymmetricKeyData_SetKey(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + const unsigned char *key_data, + uint32_t key_data_size); +static TPM_RESULT TPM_AES_ctr128_encrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const AES_KEY *aes_enc_key, + unsigned char ctr[TPM_AES_BLOCK_SIZE]); + +#endif + +/* + Initialization function +*/ + +TPM_RESULT TPM_Crypto_Init() +{ + TPM_RESULT rc = 0; + + printf("TPM_Crypto_Init: OpenSSL library %08lx\n", (unsigned long)OPENSSL_VERSION_NUMBER); + /* sanity check that the SHA1 context handling remains portable */ + if (rc == 0) { + if ((sizeof(SHA_LONG) != sizeof(uint32_t)) || + (sizeof(unsigned int) != sizeof(uint32_t)) || + (sizeof(SHA_CTX) != (sizeof(uint32_t) * (8 + SHA_LBLOCK)))) { + printf("TPM_Crypto_Init: Error(fatal), SHA_CTX has unexpected structure\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_Crypto_TestSpecific() performs any library specific tests + + For OpenSSL + */ + +TPM_RESULT TPM_Crypto_TestSpecific() +{ + TPM_RESULT rc = 0; + + /* Saving the SHA-1 context is fragile code, so test at startup */ + void *context1; + void *context2; + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + int not_equal; + TPM_STORE_BUFFER sbuffer; + const unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Crypto_TestSpecific: Test 1 - SHA1 two parts\n"); + context1 = NULL; /* freed @1 */ + context2 = NULL; /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + + if (rc== 0) { + rc = TPM_Malloc((unsigned char **)&context1, sizeof(SHA_CTX)); /* freed @1 */ + } + /* digest the first part of the array */ + if (rc== 0) { + SHA1_Init(context1); + SHA1_Update(context1, buffer1, 16); + } + /* store the SHA1 context */ + if (rc== 0) { + rc = TPM_Sha1Context_Store(&sbuffer, context1); + } + /* load the SHA1 context */ + if (rc== 0) { + TPM_Sbuffer_Get(&sbuffer, &stream, &stream_size); + rc = TPM_Sha1Context_Load + (&context2, (unsigned char **)&stream, &stream_size); /* freed @2 */ + } + /* digest the rest of the array */ + if (rc== 0) { + SHA1_Update(context2, buffer1 + 16, sizeof(buffer1) - 17); + SHA1_Final(actual, context2); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_Crypto_TestSpecific: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + free(context1); /* @1 */ + free(context2); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rc; +} + + + +/* + Random Number Functions +*/ + +/* TPM_Random() fills 'buffer' with 'bytes' bytes. + */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Random: Requesting %lu bytes\n", (unsigned long)bytes); + + if (rc == 0) { + /* openSSL call */ + rc = RAND_bytes(buffer, bytes); + if (rc == 1) { /* OSSL success */ + rc = 0; + } + else { /* OSSL failure */ + printf("TPM_Random: Error (fatal) calling RAND_bytes()\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StirRandomCmd:\n"); + if (rc == 0) { + /* NOTE: The TPM command does not give an entropy estimate. This assumes the best case */ + /* openSSL call */ + RAND_add(inData->buffer, /* buf mixed into PRNG state*/ + inData->size, /* number of bytes */ + inData->size); /* entropy, the lower bound of an estimate of how much randomness is + contained in buf */ + } + return rc; +} + +/* + RSA Functions +*/ + +/* Generate an RSA key pair. + + 'n', 'p', 'q', 'd' must be freed by the caller +*/ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, /* public key - modulus */ + unsigned char **p, /* private key prime */ + unsigned char **q, /* private key prime */ + unsigned char **d, /* private key (private exponent) */ + int num_bits, /* key size in bits */ + const unsigned char *earr, /* public exponent as an array */ + uint32_t e_size) +{ + TPM_RESULT rc = 0; + RSA *rsa = NULL; + const BIGNUM *bnn = NULL; + BIGNUM *bne = NULL; + const BIGNUM *bnp = NULL; + const BIGNUM *bnq = NULL; + const BIGNUM *bnd = NULL; + uint32_t nbytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + unsigned long e; + + /* initialize in case of error */ + printf(" TPM_RSAGenerateKeyPair:\n"); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + + /* check that num_bits is a multiple of 16. If not, the primes p and q will not be a multiple of + 8 and will not fit well in a byte */ + if (rc == 0) { + if ((num_bits % 16) != 0) { + printf("TPM_RSAGenerateKeyPair: Error, num_bits %d is not a multiple of 16\n", + num_bits); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* convert the e array to an unsigned long */ + if (rc == 0) { + rc = TPM_LoadLong(&e, earr, e_size); + } + /* validate the public exponent against a list of legal values. Some values (e.g. even numbers) + will hang the key generator. */ + if (rc == 0) { + rc = TPM_RSA_exponent_verify(e); + } + if (rc == 0) { + rsa = RSA_new(); /* freed @1 */ + if (rsa == NULL) { + printf("TPM_RSAGenerateKeyPair: Error in RSA_new()\n"); + rc = TPM_SIZE; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&bne, earr, e_size); /* freed @2 */ + } + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: num_bits %d exponent %08lx\n", num_bits, e); + int irc = RSA_generate_key_ex(rsa, num_bits, bne, NULL); + if (irc != 1) { + printf("TPM_RSAGenerateKeyPair: Error calling RSA_generate_key_ex()\n"); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { +#if defined OPENSSL_OLD_API + bnn = rsa->n; + bnp = rsa->p; + bnq = rsa->q; + bnd = rsa->d; +#else + /* currently, this function accepts NULL inputs, but it's not guaranteed by the + documentation */ + const BIGNUM *bnetmp = NULL; /* not needed */ + RSA_get0_key(rsa, &bnn, &bnetmp, &bnd); + RSA_get0_factors(rsa, &bnp, &bnq); +#endif + } + /* load n */ + if (rc == 0) { + rc = TPM_bn2binMalloc(n, &nbytes, (TPM_BIGNUM)bnn, num_bits/8); /* freed by caller */ + } + /* load p */ + if (rc == 0) { + rc = TPM_bn2binMalloc(p, &pbytes, (TPM_BIGNUM)bnp, num_bits/16); /* freed by caller */ + } + /* load q */ + if (rc == 0) { + rc = TPM_bn2binMalloc(q, &qbytes, (TPM_BIGNUM)bnq, num_bits/16); /* freed by caller */ + } + /* load d */ + if (rc == 0) { + rc = TPM_bn2binMalloc(d, &dbytes, (TPM_BIGNUM)bnd, num_bits/8); /* freed by caller */ + } + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: length of n,p,q,d = %d / %d / %d / %d\n", + nbytes, pbytes, qbytes, dbytes); + } + if (rc != 0) { + free(*n); + free(*p); + free(*q); + free(*d); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + } + if (rsa != NULL) { + RSA_free(rsa); /* @1 */ + } + if (bne != NULL) { + BN_free(bne); /* @2 */ + } + return rc; +} + +/* TPM_RSAGeneratePublicToken() generates an RSA key token from n and e + */ + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSA **rsa_pub_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + BIGNUM * n = NULL; + BIGNUM * e = NULL; + + /* sanity check for the free */ + if (rc == 0) { + if (*rsa_pub_key != NULL) { + printf("TPM_RSAGeneratePublicToken: Error (fatal), token %p should be NULL\n", + *rsa_pub_key ); + rc = TPM_FAIL; + + } + } + /* construct the OpenSSL private key object */ + if (rc == 0) { + *rsa_pub_key = RSA_new(); /* freed by caller */ + if (*rsa_pub_key == NULL) { + printf("TPM_RSAGeneratePublicToken: Error in RSA_new()\n"); + rc = TPM_SIZE; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed by caller */ + } + if (rc == 0) { +#if defined OPENSSL_OLD_API + (*rsa_pub_key)->n = n; + (*rsa_pub_key)->e = e; + (*rsa_pub_key)->d = NULL; +#else + int irc = RSA_set0_key(*rsa_pub_key, n, e, NULL); + if (irc != 1) { + printf("TPM_RSAGeneratePublicToken: Error in RSA_set0_key()\n"); + rc = TPM_SIZE; + } +#endif + } + return rc; +} + +/* TPM_RSAGeneratePrivateToken() generates an RSA key token from n,e,d + */ + +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSA **rsa_pri_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + BIGNUM * n = NULL; + BIGNUM * e = NULL; + BIGNUM * d = NULL; + + /* sanity check for the free */ + if (rc == 0) { + if (*rsa_pri_key != NULL) { + printf("TPM_RSAGeneratePrivateToken: Error (fatal), token %p should be NULL\n", + *rsa_pri_key ); + rc = TPM_FAIL; + + } + } + /* construct the OpenSSL private key object */ + if (rc == 0) { + *rsa_pri_key = RSA_new(); /* freed by caller */ + if (*rsa_pri_key == NULL) { + printf("TPM_RSAGeneratePrivateToken: Error in RSA_new()\n"); + rc = TPM_SIZE; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&d, darr, dbytes); /* freed by caller */ + } + if (rc == 0) { +#if defined OPENSSL_OLD_API + (*rsa_pri_key)->n = n; + (*rsa_pri_key)->e = e; + (*rsa_pri_key)->d = d; + BN_set_flags(d, BN_FLG_CONSTTIME); // d is private +#else + int irc = RSA_set0_key(*rsa_pri_key, n, e, d); + if (irc != 1) { + printf("TPM_RSAGeneratePrivateToken: Error in RSA_set0_key()\n"); + rc = TPM_SIZE; + } +#endif + } + return rc; +} + +#if !USE_OPENSSL_FUNCTIONS_RSA // libtpms added +/* TPM_RSAPrivateDecrypt() decrypts 'encrypt_data' using the private key 'n, e, d'. The OAEP + padding is removed and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + size_t decrypt_data_size, /* size of decrypt_data buffer */ + TPM_ENC_SCHEME encScheme, /* encryption scheme */ + unsigned char *encrypt_data, /* encrypted data */ + uint32_t encrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA * rsa_pri_key = NULL; /* freed @1 */ + + unsigned char *padded_data = NULL; + int padded_data_size = 0; + + printf(" TPM_RSAPrivateDecrypt:\n"); + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + /* the size of the decrypted data is guaranteed to be less than this */ + padded_data_size = RSA_size(rsa_pri_key); + rc = TPM_Malloc(&padded_data, padded_data_size); + } + if (rc == 0) { + /* decrypt with private key. Must decrypt first and then remove padding because the decrypt + call cannot specify an encoding parameter */ + /* returns the size of the encrypted data. On error, -1 is returned */ + irc = RSA_private_decrypt(encrypt_data_size, /* length */ + encrypt_data, /* from - the encrypted data */ + padded_data, /* to - the decrypted but padded data */ + rsa_pri_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_private_decrypt()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_private_decrypt() success\n"); + printf(" TPM_RSAPrivateDecrypt: Padded data size %u\n", padded_data_size); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt padded data", padded_data); + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + /* openSSL expects the padded data to skip the first 0x00 byte, since it expects the + padded data to come from a bignum via bn2bin. */ + irc = RSA_padding_check_PKCS1_OAEP(decrypt_data, /* to */ + decrypt_data_size, /* to length */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + encrypt_data_size, /* rsa_len */ + tpm_oaep_pad_str, /* encoding parameter */ + sizeof(tpm_oaep_pad_str) /* encoding parameter length + */ + ); + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_padding_check_PKCS1_OAEP()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + irc = RSA_padding_check_PKCS1_type_2(decrypt_data, /* to */ + decrypt_data_size, /* to length */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + encrypt_data_size /* rsa_len */ + ); + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_padding_check_PKCS1_type_2()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + else { + printf("TPM_RSAPrivateDecrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + *decrypt_data_length = irc; + printf(" TPM_RSAPrivateDecrypt: RSA_padding_check_PKCS1_OAEP() recovered %d bytes\n", irc); + TPM_PrintFourLimit(" TPM_RSAPrivateDecrypt: Decrypt data", decrypt_data, *decrypt_data_length); + } + if (rsa_pri_key != NULL) { + RSA_free(rsa_pri_key); /* @1 */ + } + free(padded_data); /* @2 */ + return rc; +} + +#else // libtpms added begin + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + size_t decrypt_data_size, /* size of decrypt_data buffer */ + TPM_ENC_SCHEME encScheme, /* encryption scheme */ + unsigned char *encrypt_data, /* encrypted data */ + uint32_t encrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md = NULL; + unsigned char *label = NULL; + size_t outlen; + unsigned char buffer[(TPM_RSA_KEY_LENGTH_MAX + 7) / 8]; + + printf(" TPM_RSAPrivateDecrypt:\n"); + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGenerateEVP_PKEY(&pkey, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + + if (rc == 0) { + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == 0) { + printf("TPM_RSAPrivateDecrypt: Error in EVP_PKEY_CTX_new()\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (EVP_PKEY_decrypt_init(ctx) <= 0) { + printf("TPM_RSAPrivateDecrypt: Error in EVP_PKEY_decrypt_init()\n"); + rc = TPM_FAIL; + } + } + + if (rc == 0) { + switch (encScheme) { + case TPM_ES_RSAESOAEP_SHA1_MGF1: + if (rc == 0) { + md = EVP_get_digestbyname("sha1"); + if (md == NULL || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) { + printf("TPM_RSAPrivateDecrypt: Error in setting up decrypt context for TPM_ES_RSAESOAEP_SHA1_MGF\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc(&label, sizeof(tpm_oaep_pad_str)); + if (rc) { + printf("TPM_RSAPrivateDecrypt: TPM_Malloc failed\n"); + } + } + if (rc == 0) { + memcpy(label, tpm_oaep_pad_str, sizeof(tpm_oaep_pad_str)); + if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label, sizeof(tpm_oaep_pad_str)) <= 0) { + printf("TPM_RSAPrivateDecrypt: EVP_PKEY_CTX_set0_rsa_oaep_label() failed\n"); + rc = TPM_FAIL; + } + if (rc == 0) { + label = NULL; + } + } + break; + case TPM_ES_RSAESPKCSv15: + if (rc == 0) { + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + printf("TPM_RSAPrivateDecrypt: Error in setting up decrypt context for TPM_ES_RSAESPKCSv15\n"); + rc = TPM_FAIL; + } + } + break; + default: + if (rc == 0) { + printf("TPM_RSAPrivateDecrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + } + + if (rc == 0) { + outlen = sizeof(buffer); + if (EVP_PKEY_decrypt(ctx, buffer, &outlen, + encrypt_data, encrypt_data_size) <= 0) { + printf("TPM_RSAPrivateDecrypt: EVP_PKEY_decrypt failed\n"); + rc = TPM_DECRYPT_ERROR; + } + if (rc == 0) { + if (outlen > decrypt_data_size) { + printf("TPM_RSAPrivateDecrypt: Error, decrypt_data_size %u too small for message size %u\n", + decrypt_data_size, outlen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + *decrypt_data_length = (uint32_t)outlen; + memcpy(decrypt_data, buffer, outlen); + TPM_PrintFourLimit(" TPM_RSAPrivateDecrypt: Decrypt data", decrypt_data, *decrypt_data_length); + } + } + + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + TPM_Free(label); + + return rc; +} + +#endif // libtpms added end + +/* TPM_RSAPublicEncrypt() pads 'decrypt_data' to 'encrypt_data_size' and encrypts using the public + key 'n, e'. +*/ + +#if !USE_OPENSSL_FUNCTIONS_RSA // libtpms added + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char* encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + TPM_ENC_SCHEME encScheme, + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA *rsa_pub_key = NULL; + unsigned char *padded_data = NULL; + + printf(" TPM_RSAPublicEncrypt: Input data size %lu\n", (unsigned long)decrypt_data_size); + /* intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, encrypt_data_size); /* freed @2 */ + } + /* construct the OpenSSL public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + irc = RSA_padding_add_PKCS1_OAEP(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size, /* from length */ + tpm_oaep_pad_str, /* encoding parameter */ + sizeof(tpm_oaep_pad_str) /* encoding parameter length + */ + ); + if (irc != 1) { + printf("TPM_RSAPublicEncrypt: Error in RSA_padding_add_PKCS1_OAEP()\n"); + rc = TPM_ENCRYPT_ERROR; + } + else { + printf(" TPM_RSAPublicEncrypt: RSA_padding_add_PKCS1_OAEP() success\n"); + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + irc = RSA_padding_add_PKCS1_type_2(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size); /* from length */ + if (irc != 1) { + printf("TPM_RSAPublicEncrypt: Error in RSA_padding_add_PKCS1_type_2()\n"); + rc = TPM_ENCRYPT_ERROR; + } + else { + printf(" TPM_RSAPublicEncrypt: RSA_padding_add_PKCS1_type_2() success\n"); + } + } + else { + printf("TPM_RSAPublicEncrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt: Padded data size %lu\n", (unsigned long)encrypt_data_size); + TPM_PrintFour(" TPM_RSAPublicEncrypt: Padded data", padded_data); + /* encrypt with public key. Must pad first and then encrypt because the encrypt + call cannot specify an encoding parameter */ + /* returns the size of the encrypted data. On error, -1 is returned */ + irc = RSA_public_encrypt(encrypt_data_size, /* from length */ + padded_data, /* from - the clear text data */ + encrypt_data, /* the padded and encrypted data */ + rsa_pub_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPublicEncrypt: Error in RSA_public_encrypt()\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt: RSA_public_encrypt() success\n"); + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + free(padded_data); /* @2 */ + return rc; +} + +#else // libtpms added begin + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char* encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + TPM_ENC_SCHEME encScheme, + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md = NULL; + unsigned char *label = NULL; + size_t outlen; + + printf(" TPM_RSAPublicEncrypt: Input data size %lu\n", (unsigned long)decrypt_data_size); + + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGenerateEVP_PKEY(&pkey, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + NULL, /* private exponent */ + 0); + } + + if (rc == 0) { + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == 0) { + printf("TPM_RSAqPrivateDecrypt: Error in EVP_PKEY_CTX_new()\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (EVP_PKEY_encrypt_init(ctx) <= 0) { + printf("TPM_RSAPrivateDecrypt: Error in EVP_PKEY_decrypt_init()\n"); + rc = TPM_FAIL; + } + } + + if (rc == 0) { + switch (encScheme) { + case TPM_ES_RSAESOAEP_SHA1_MGF1: + if (rc == 0) { + md = EVP_get_digestbyname("sha1"); + if (md == NULL || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) { + printf("TPM_RSAPublicEncrypt: Error in setting up encrypt context for TPM_ES_RSAESOAEP_SHA1_MGF\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc(&label, sizeof(tpm_oaep_pad_str)); + if (rc) { + printf("TPM_RSAPublicEncrypt: TPM_Malloc failed\n"); + } + } + if (rc == 0) { + memcpy(label, tpm_oaep_pad_str, sizeof(tpm_oaep_pad_str)); + if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label, sizeof(tpm_oaep_pad_str)) <= 0) { + printf("TPM_RSAPublicEncrypt: EVP_PKEY_CTX_set0_rsa_oaep_label() failed\n"); + rc = TPM_FAIL; + } + if (rc == 0) { + label = NULL; + } + } + break; + case TPM_ES_RSAESPKCSv15: + if (rc == 0) { + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + printf("TPM_RSAPublicEncrypt: Error in setting up encrypt context for TPM_ES_RSAESPKCSv15\n"); + rc = TPM_FAIL; + } + } + break; + default: + if (rc == 0) { + printf("TPM_RSAPublicEncrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + } + + if (rc == 0) { + outlen = encrypt_data_size; + if (EVP_PKEY_encrypt(ctx, encrypt_data, &outlen, + decrypt_data, decrypt_data_size) <= 0) { + printf("TPM_RSAPublicEncrypt: EVP_PKEY_encrypt failed\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + TPM_Free(label); + + return rc; +} + +#endif // libtpms added end + +#if USE_FREEBL_CRYPTO_LIBRARY +/* TPM_RSAPublicEncryptRaw() does a raw public key operation without any padding. + +*/ + +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, /* output */ + uint32_t encrypt_data_size, /* input, size of message buffer */ + unsigned char *decrypt_data, /* input */ + uint32_t decrypt_data_size, /* input, size of sig buffer */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA *rsa_pub_key = NULL; + + printf(" TPM_RSAPublicEncryptRaw:\n"); + /* the input data size must equal the public key size */ + if (rc == 0) { + if (decrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, decrypt data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* the output data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, Encrypted data size is %u not %u\n", + encrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* construct the OpenSSL public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Public modulus", narr); + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Public exponent", earr, ebytes); + TPM_PrintFourLimit(" TPM_RSAPublicEncryptRaw: Decrypt data", decrypt_data, decrypt_data_size); + /* encrypt the decrypt_data */ + irc = RSA_public_encrypt(decrypt_data_size, /* from length */ + decrypt_data, /* from - the clear text data */ + encrypt_data, /* to - the padded and encrypted data */ + rsa_pub_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPublicEncryptRaw: Error in RSA_public_encrypt()\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Encrypt data", encrypt_data); +#if 0 /* NOTE: Uncomment as a debug aid for signature verification */ + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Padded signed data", + encrypt_data, encrypt_data_size); +#endif + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + return rc; +} +#endif + +/* TPM_RSASign() signs 'message' of size 'message_size' using the private key n,e,d and the + signature scheme 'sigScheme' as specified in PKCS #1 v2.0. + + 'signature_length' bytes are moved to 'signature'. 'signature_length' is at most + 'signature_size'. signature must point to RSA_size(rsa) bytes of memory. +*/ +/* Note regarding conversion to EVP_PKEY_sign for the purpose of constant-timeness: + + - TPM_SS_RSASSAPKCS1v15_SHA1: + EVP_PKEY_sign() will call pkey_rsa_sign() which in turn will call RSA_sign() for + RSA_PKCS1_PADDING. This is the same as we do here. + - TPM_SS_RSASSAPKCS1v15_DER: + EVP_PKEY_sign() must not have a message digest since none of the padding choices calls + RSA_padding_add_PKCS1_type_1(), so we would have to do the padding again ourselves. +*/ + +TPM_RESULT TPM_RSASign(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + RSA * rsa_pri_key = NULL; /* freed @1 */ + unsigned int key_size; + + printf(" TPM_RSASign:\n"); + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* check the size of the output signature buffer */ + if (rc == 0) { + key_size = (unsigned int)RSA_size(rsa_pri_key); /* openSSL returns an int, but never + negative */ + if (signature_size < key_size) { + printf("TPM_RSASign: Error (fatal), buffer %u too small for signature %u\n", + signature_size, key_size); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSASign: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSASignSHA1(signature, + signature_length, + message, + message_size, + rsa_pri_key); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + rc = TPM_RSASignDER(signature, + signature_length, + message, + message_size, + rsa_pri_key); + break; + default: + printf("TPM_RSASign: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + if (rsa_pri_key != NULL) { + RSA_free(rsa_pri_key); /* @1 */ + } + return rc; +} + +/* TPM_RSASignSHA1() performs the following: + prepend a DER encoded algorithm ID + prepend a type 1 pad + encrypt with the private key +*/ + +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSA *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_RSASignSHA1:\n"); + /* sanity check, SHA1 messages must be 20 bytes */ + if (rc == 0) { + if (message_size != TPM_DIGEST_SIZE) { + printf("TPM_RSASignSHA1: Error, message size %lu not TPM_DIGEST_SIZE\n", + (unsigned long)message_size ); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* type NID_sha1, adds the algorithm identifier and type 1 pad */ + irc = RSA_sign(NID_sha1, /* type */ + message, message_size, + signature, signature_length, + rsa_pri_key); + /* RSA_sign() returns 1 on success, 0 otherwise. */ + if (irc != 1) { + printf("TPM_RSASignSHA1: Error in RSA_sign()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + return rc; +} + +/* TPM_RSASignDER() performs the following: + + prepend a type 1 pad + encrypt with the private key + + The caller must check that the signature buffer is >= the key size. +*/ + +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSA *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + int irc; + int key_size; + unsigned char *message_pad; + int int_sig_len; /* openSSL overloads RSA_private_decrypt return code */ + + printf(" TPM_RSASignDER:\n"); + message_pad = NULL; /* freed @1 */ + /* the padded message size is the same as the key size */ + if (rc == 0) { + key_size = RSA_size(rsa_pri_key); + if (key_size < 0) { + printf(" TPM_RSASignDER: Error (fatal), negative key size %d\n", key_size); + rc = TPM_FAIL; /* should never occur */ + } + } + /* allocate memory for the padded message */ + if (rc == 0) { + printf(" TPM_RSASignDER: key size %d\n", key_size); + rc = TPM_Malloc(&message_pad, key_size); /* freed @1 */ + } + /* PKCS1 type 1 pad the message */ + if (rc == 0) { + printf(" TPM_RSASignDER: Applying PKCS1 type 1 padding, size from %lu to %u\n", + (unsigned long)message_size, key_size); + TPM_PrintFourLimit(" TPM_RSASignDER: Input message", message, message_size); + /* This call checks that the message will fit with the padding */ + irc = RSA_padding_add_PKCS1_type_1(message_pad, /* to */ + key_size, + message, /* from */ + message_size); + if (irc != 1) { + printf("TPM_RSASignDER: Error padding message, size %lu key size %u\n", + (unsigned long)message_size, key_size); + rc = TPM_DECRYPT_ERROR; + } + } + /* raw sign with private key */ + if (rc == 0) { + printf(" TPM_RSASignDER: Encrypting with private key, message size %d\n", key_size); + TPM_PrintFour(" TPM_RSASignDER: Padded message", message_pad); + /* returns the size of the encrypted data. On error, -1 is returned */ + int_sig_len = RSA_private_encrypt(key_size, /* int flen */ + message_pad, /* unsigned char *from, */ + signature, /* unsigned char *to, */ + rsa_pri_key, /* RSA *rsa, */ + RSA_NO_PADDING); /* int padding); */ + if (int_sig_len >= 0) { + *signature_length = (unsigned int)int_sig_len; + } + else { + printf("TPM_RSASignDER: Error in RSA_private_encrypt()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignDER: signature", signature); + } + free(message_pad); /* @1 */ + return rc; +} + +/* TPM_RSAVerifySHA1() performs the following: + decrypt the signature + verify and remove type 1 pad + verify and remove DER encoded algorithm ID + verify the signature on the message +*/ + +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature + buffer */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + TPM_BOOL valid; + RSA * rsa_pub_key = NULL; + + printf(" TPM_RSAVerifySHA1:\n"); + /* construct the openSSL public key object from n and e */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + /* RSA_verify() returns 1 on successful verification, 0 otherwise. */ + valid = RSA_verify(NID_sha1, + message, message_size, + signature, signature_size, rsa_pub_key); + if (valid != 1) { + printf("TPM_RSAVerifySHA1: Error, bad signature\n"); + rc = TPM_BAD_SIGNATURE; + } + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + return rc; +} + +/* TPM_RSAGetPrivateKey recalculates q (2nd prime factor) and d (private key) from n (public key), e + (public exponent), and p (1st prime factor) + + The private key is validated by dividing the RSA product n by the RSA prime p and verifying that + the remainder is 0. + + 'qarr', darr' must be freed by the caller. +*/ + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr) +{ + TPM_RESULT rc = 0; /* TPM return code */ + int irc; /* openSSL return code */ + BIGNUM *brc; /* BIGNUM return code */ + + BIGNUM *n = NULL; /* public modulus */ + BIGNUM *e = NULL; /* public exponent */ + BIGNUM *d = NULL; /* private exponent */ + BIGNUM *p = NULL; /* secret prime factor */ + BIGNUM *q = NULL; /* secret prime factor */ + /* temporary variables */ + BN_CTX *ctx = NULL; /* freed @5, @6 */ + BIGNUM *r0 = NULL; /* n/p remainder */ + BIGNUM *r1 = NULL; + BIGNUM *r2 = NULL; + + /* set to NULL so caller can free after failure */ + printf(" TPM_RSAGetPrivateKey:\n"); + *qarr = NULL; + *darr = NULL; + /* check input parameters */ + if (rc == 0) { + if ((narr == NULL) || (nbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing n\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((earr == NULL) || (ebytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing e\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((parr == NULL) || (pbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing p\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* get some temporary BIGNUM's for use in the calculations */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + if (rc == 0) { + BN_CTX_start(ctx); /* no return code */ + r0 = BN_CTX_get(ctx); /* sufficient to test return of last 'get' call */ + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + if (r2 == 0) { + printf("TPM_RSAGetPrivateKey: Error in BN_CTX_get()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + } + /* allocate BIGNUM's for q, d */ + if (rc == 0) { + rc = TPM_BN_new((TPM_BIGNUM *)&q); + } + if (rc == 0) { + rc = TPM_BN_new((TPM_BIGNUM *)&d); + } + /* convert n, e, p to BIGNUM's */ + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed @2 */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&p, parr, pbytes); /* freed @3 */ + if (p) + BN_set_flags(p, BN_FLG_CONSTTIME); // p is private + } + /* calculate q = n/p */ + if (rc == 0) { + irc = BN_div(q, r0, n, p, ctx); /* q = n/p freed @4 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_div()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } else + BN_set_flags(q, BN_FLG_CONSTTIME); // q is private + } + /* remainder should be zero */ + if (rc == 0) { + irc = BN_is_zero(r0); + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_is_zero()\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r0 = p-1 */ + if (rc == 0) { + irc = BN_sub(r0, p, BN_value_one()); /* r0 = p-1 freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_sub()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r1 = q-1 */ + if (rc == 0) { + irc = BN_sub(r1, q, BN_value_one()); /* freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_sub()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r2 = (p-1)(q-1) */ + if (rc == 0) { + irc = BN_mul(r2, r0, r1, ctx); /* freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } else + BN_set_flags(r2, BN_FLG_CONSTTIME); // r2 is private + } + /* calculate d = multiplicative inverse e mod r0 */ + if (rc == 0) { + brc = BN_mod_inverse(d, e, r2, ctx); /* feed @5 */ + if (brc == NULL) { + printf("TPM_RSAGetPrivateKey: Error in BN_mod_inverse()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* get q as an array */ + if (rc == 0) { + rc = TPM_bn2binMalloc(qarr, qbytes, (TPM_BIGNUM)q, pbytes); /* freed by caller */ + } + /* get d as an array */ + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated q", *qarr); + rc = TPM_bn2binMalloc(darr, dbytes, (TPM_BIGNUM)d, nbytes); /* freed by caller */ + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated d", *darr); + printf(" TPM_RSAGetPrivateKey: length of n,p,q,d = %u / %u / %u / %u\n", + nbytes, pbytes, *qbytes, *dbytes); + } + BN_free(n); /* @1 */ + BN_free(e); /* @2 */ + BN_free(p); /* @3 */ + BN_free(q); /* @4 */ + BN_free(d); /* @3 */ + BN_CTX_end(ctx); /* @5 */ + BN_CTX_free(ctx); /* @6 */ + return rc; +} + +/* + openSSL wrappers do error logging and transformation of openSSL errors to TPM type errors +*/ + +/* TPM_OpenSSL_PrintError() prints a detailed openSSL error trace. + +*/ + +static void TPM_OpenSSL_PrintError() +{ + /* openssl error printing */ + unsigned long error; + const char *file; + int line; + const char *data; + int flags; + + error = ERR_get_error_line_data(&file, &line, &data, &flags); + printf("\terror %08lx file %s line %d data %s flags %08x\n", + error, file, line, data, flags); + return; +} + +/* TPM_BN_num_bytes() wraps the openSSL function in a TPM error handler + + Returns number of bytes in the input +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + int i; + BIGNUM *bn = (BIGNUM *)bn_in; + + i = BN_num_bytes(bn); + if (i >= 0) { + *numBytes = (unsigned int)i; + } + else { + printf("TPM_BN_num_bytes: Error (fatal), bytes in BIGNUM is negative\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_BN_is_one() wraps the openSSL function in a TPM error handler + + Returns success if input is 1 + */ + +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *bn = (BIGNUM *)bn_in; + + /* int BN_is_one(BIGNUM *a); + BN_is_one() tests if a equals 0, 1, + BN_is_one() returns 1 if the condition is true, 0 otherwise. */ + irc = BN_is_one(bn); + if (irc != 1) { + printf("TPM_BN_is_one: Error, result is not 1\n"); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + +/* TPM_BN_mod() wraps the openSSL function in a TPM error handler + + r = a mod m + */ + +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *rem = (BIGNUM *)rem_in; + BIGNUM *a = (BIGNUM *)a_in; + BIGNUM *m = (BIGNUM *)m_in; + BN_CTX *ctx = NULL; /* freed @1 */ + + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); /* freed @1 */ + } + /*int BN_mod(BIGNUM *rem, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); + BN_mod() corresponds to BN_div() with dv set to NULL. + + int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a, const BIGNUM *d, BN_CTX *ctx); + + BN_div() divides a by d and places the result in dv and the remainder in rem (dv=a/d, + rem=a%d). Either of dv and rem may be NULL, in which case the respective value is not + returned. The result is rounded towards zero; thus if a is negative, the remainder will be + zero or negative. For division by powers of 2, use BN_rshift(3). + + For all functions, 1 is returned for success, 0 on error. The return value should always be + checked + */ + irc = BN_mod(rem, a, m, ctx); + if (irc != 1) { + printf("TPM_BN_mod: Error performing BN_mod()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mask_bits() wraps the openSSL function in a TPM error handler + + erase all but the lowest n bits of bn + bn = bn mod 2^^n +*/ + +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n) +{ + TPM_RESULT rc = 0; + int irc; + unsigned int numBytes; + BIGNUM *bn = (BIGNUM *)bn_in; + + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, bn_in); + } + /* if the BIGNUM is already the correct number of bytes, no need to mask, and BN_mask_bits() + will fail. */ + if (rc == 0) { + if (numBytes > (n / 8)) { + /* BN_mask_bits() truncates a to an n bit number (a&=~((~0)>>;n)). An error occurs if a + already is shorter than n bits. + + int BN_mask_bits(BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_mask_bits(bn, n); + if (irc != 1) { + printf("TPM_BN_mask_bits: Error performing BN_mask_bits()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + } + return rc; +} + +/* TPM_BN_rshift() wraps the openSSL function in a TPM error handler + + Shift a right by n bits (discard the lowest n bits) and label the result r +*/ + +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM **rBignum = (BIGNUM **)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + + printf(" TPM_BN_rshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* BN_rshift() shifts a right by n bits and places the result in r (r=a/2^n). + int BN_rshift(BIGNUM *r, BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_rshift(*rBignum, aBignum, n); + if (irc != 1) { + printf("TPM_BN_rshift: Error performing BN_rshift()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + return rc; +} + +/* TPM_BN_lshift() wraps the openSSL function in a TPM error handler + + Shift a left by n bits and label the result r +*/ + +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM **rBignum = (BIGNUM **)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + + printf(" TPM_BN_lshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* BN_lshift() shifts a left by n bits and places the result in r (r=a*2^n). + int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_lshift(*rBignum, aBignum, n); + if (irc != 1) { + printf("TPM_lshift: Error performing BN_lshift()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + return rc; +} + +/* TPM_BN_add() wraps the openSSL function in a TPM error handler + + Performs R = A + B + + R may be the same as A or B +*/ + +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + + printf(" TPM_BN_add:\n"); + /* int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + BN_add() adds a and b and places the result in r (r=a+b). r may be the same BIGNUM as a or b. + 1 is returned for success, 0 on error. + */ + irc = BN_add(rBignum, aBignum, bBignum); + if (irc != 1) { + printf("TPM_BN_add: Error performing BN_add()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + +/* TPM_BN_mul() wraps the openSSL function in a TPM error handler + + r = a * b +*/ + +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + + printf(" TPM_BN_mul:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); /* freed @1 */ + } + /* int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx); + BN_mul() multiplies a and b and places the result in r (r=a*b). r may be the same BIGNUM as a + or b. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mul(rBignum, aBignum, bBignum, ctx); + if (irc != 1) { + printf("TPM_BN_add: Error performing BN_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mod_exp() wraps the openSSL function in a TPM error handler + + computes a to the p-th power modulo m (r=a^p % n) +*/ + +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *pBignum = (BIGNUM *)pBignum_in; + BIGNUM *nBignum = (BIGNUM *)nBignum_in; + + printf(" TPM_BN_mod_exp:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* BIGNUM calculation */ + /* int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx); + + BN_mod_exp() computes a to the p-th power modulo m (r=a^p % m). This function uses less time + and space than BN_exp(). + + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + printf(" TPM_BN_mod_exp: Calculate mod_exp\n"); + BN_set_flags(pBignum, BN_FLG_CONSTTIME); // p may be private + irc = BN_mod_exp(rBignum, aBignum, pBignum, nBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_exp: Error performing BN_mod_exp()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_Mod_add() wraps the openSSL function in a TPM error handler + + adds a to b modulo m +*/ + +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + BIGNUM *mBignum = (BIGNUM *)mBignum_in; + + printf(" TPM_BN_mod_add:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* int BN_mod_add(BIGNUM *r, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); + BN_mod_add() adds a to b modulo m and places the non-negative result in r. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mod_add(rBignum, aBignum, bBignum, mBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_add: Error performing BN_mod_add()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mod_mul() wraps the openSSL function in a TPM error handler + + r = (a * b) mod m + */ + +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + BIGNUM *mBignum = (BIGNUM *)mBignum_in; + + printf(" TPM_BN_mod_mul:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* int BN_mod_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); + BN_mod_mul() multiplies a by b and finds the non-negative remainder respective to modulus m + (r=(a*b) mod m). r may be the same BIGNUM as a or b. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mod_mul(rBignum, aBignum, bBignum, mBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_mul: Error performing BN_mod_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_CTX_new() wraps the openSSL function in a TPM error handler */ + +static TPM_RESULT TPM_BN_CTX_new(BN_CTX **ctx) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (*ctx != NULL) { + printf("TPM_BN_CTX_new: Error (fatal), *ctx %p should be NULL before BN_CTX_new \n", + *ctx); + rc = TPM_FAIL; + } + } + if (rc == 0) { + *ctx = BN_CTX_new(); + if (*ctx == NULL) { + printf("TPM_BN_CTX_new: Error, context is NULL\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + + } + } + return rc; +} + +/* TPM_BN_new() wraps the openSSL function in a TPM error handler + + Allocates a new bignum +*/ + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in) +{ + TPM_RESULT rc = 0; + BIGNUM **bn = (BIGNUM **)bn_in; + + *bn = BN_new(); + if (*bn == NULL) { + printf("TPM_BN_new: Error, bn is NULL\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + return rc; +} + +/* TPM_BN_free() wraps the openSSL function + + Frees the bignum +*/ + +void TPM_BN_free(TPM_BIGNUM bn_in) +{ + BIGNUM *bn = (BIGNUM *)bn_in; + + BN_free(bn); + return; +} + +/* TPM_bn2bin wraps the openSSL function in a TPM error handler. + + Converts a bignum to char array + + 'bin' must already be checked for sufficient size. + + int BN_bn2bin(const BIGNUM *a, unsigned char *to); + BN_bn2bin() returns the length of the big-endian number placed at to +*/ + +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + BN_bn2bin((BIGNUM *)bn_in, bin); + return rc; +} + + +/* TPM_bin2bn() wraps the openSSL function in a TPM error handler + + Converts a char array to bignum + + bn must be freed by the caller. +*/ + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, const unsigned char *bin, unsigned int bytes) +{ + TPM_RESULT rc = 0; + BIGNUM **bn = (BIGNUM **)bn_in; + + /* BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret); + + BN_bin2bn() converts the positive integer in big-endian form of length len at s into a BIGNUM + and places it in ret. If ret is NULL, a new BIGNUM is created. + + BN_bin2bn() returns the BIGNUM, NULL on error. + */ + if (rc == 0) { + *bn = BN_bin2bn(bin, bytes, *bn); + if (*bn == NULL) { + printf("TPM_bin2bn: Error in BN_bin2bn\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + } + return rc; +} + +/* + Hash Functions +*/ + +/* for the openSSL version, TPM_SHA1Context is a SHA_CTX structure */ + +/* TPM_SHA1InitCmd() initializes a platform dependent TPM_SHA1Context structure. + + The structure must be freed using TPM_SHA1Delete() +*/ + +TPM_RESULT TPM_SHA1InitCmd(void **context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1InitCmd:\n"); + if (rc== 0) { + rc = TPM_Malloc((unsigned char **)context, sizeof(SHA_CTX)); + } + if (rc== 0) { + SHA1_Init(*context); + } + return rc; +} + +/* TPM_SHA1UpdateCmd() adds 'data' of 'length' to the SHA-1 context + */ + +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1Update: length %u\n", length); + if (context != NULL) { + SHA1_Update(context, data, length); + } + else { + printf("TPM_SHA1Update: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1FinalCmd() extracts the SHA-1 digest 'md' from the context + */ + +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1FinalCmd:\n"); + if (context != NULL) { + SHA1_Final(md, context); + } + else { + printf("TPM_SHA1FinalCmd: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1Delete() zeros and frees the SHA1 context */ + +void TPM_SHA1Delete(void **context) +{ + if (*context != NULL) { + printf(" TPM_SHA1Delete:\n"); + /* zero because the SHA1 context might have data left from an HMAC */ + memset(*context, 0, sizeof(SHA_CTX)); + free(*context); + *context = NULL; + } + return; +} + +/* TPM_Sha1Context_Load() is non-portable code to deserialize the OpenSSL SHA1 context. + + If the contextPresent prepended by TPM_Sha1Context_Store() is FALSE, context remains NULL. If + TRUE, context is allocated and loaded. +*/ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + SHA_CTX *sha_ctx = NULL; /* initialize to silence hopefully bogus gcc 4.4.4 + warning */ + TPM_BOOL contextPresent; /* is there a context to be loaded */ + + printf(" TPM_Sha1Context_Load: OpenSSL\n"); + /* TPM_Sha1Context_Store() stored a flag to indicate whether a context should be stored */ + if (rc== 0) { + rc = TPM_LoadBool(&contextPresent, stream, stream_size); + printf(" TPM_Sha1Context_Load: contextPresent %u\n", contextPresent); + } + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_CheckTag(TPM_TAG_SHA1CONTEXT_OSSL_V1, stream, stream_size); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Malloc((unsigned char **)context, sizeof(SHA_CTX)); + sha_ctx = (SHA_CTX *)*context; + } + /* load h0 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h0), stream, stream_size); + } + /* load h1 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h1), stream, stream_size); + } + /* load h2 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h2), stream, stream_size); + } + /* load h3 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h3), stream, stream_size); + } + /* load h4 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h4), stream, stream_size); + } + /* load Nl */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->Nl), stream, stream_size); + } + /* load Nh */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->Nh), stream, stream_size); + } + /* load data */ + for (i = 0 ; (rc == 0) && contextPresent && (i < SHA_LBLOCK) ; i++) { + rc = TPM_Load32(&(sha_ctx->data[i]), stream, stream_size); + } + /* load num */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->num), stream, stream_size); + } + return rc; +} + +/* TPM_Sha1Context_Store() is non-portable code to serialize the OpenSSL SHA1 context. context is + not altered. + + It prepends a contextPresent flag to the stream, FALSE if context is NULL, TRUE if not. +*/ + +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context) +{ + TPM_RESULT rc = 0; + size_t i; + SHA_CTX *sha_ctx = (SHA_CTX *)context; + TPM_BOOL contextPresent; /* is there a context to be stored */ + + printf(" TPM_Sha1Context_Store: OpenSSL\n"); + /* store contextPresent */ + if (rc == 0) { + if (sha_ctx != NULL) { + printf(" TPM_Sha1Context_Store: Storing context\n"); + contextPresent = TRUE; + } + else { + printf(" TPM_Sha1Context_Store: No context to store\n"); + contextPresent = FALSE; + } + rc = TPM_Sbuffer_Append(sbuffer, &contextPresent, sizeof(TPM_BOOL)); + } + /* overall format tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SHA1CONTEXT_OSSL_V1); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h0); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h1); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h2); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h3); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h4); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->Nl); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->Nh); + } + for (i = 0 ; (rc == 0) && contextPresent && (i < SHA_LBLOCK) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->data[i]); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->num); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +/* TPM_SymmetricKeyData_New() allocates memory for and initializes a TPM_SYMMETRIC_KEY_DATA token. + */ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_New:\n"); + if (rc == 0) { + rc = TPM_Malloc(tpm_symmetric_key_data, sizeof(TPM_SYMMETRIC_KEY_DATA)); + } + if (rc == 0) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Free() initializes the key token to wipe secrets. It then frees the + TPM_SYMMETRIC_KEY_DATA token and sets it to NULL. +*/ + +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + printf(" TPM_SymmetricKeyData_Free:\n"); + if (*tpm_symmetric_key_data != NULL) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + free(*tpm_symmetric_key_data); + *tpm_symmetric_key_data = NULL; + } + return; +} + +#ifdef TPM_DES + +/* TPM_SymmetricKeyData_Init() is DES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + memset(tpm_symmetric_key_data->des_cblock1, 0, sizeof(DES_cblock)); + memset(tpm_symmetric_key_data->des_cblock2, 0, sizeof(DES_cblock)); + memset(tpm_symmetric_key_data->des_cblock3, 0, sizeof(DES_cblock)); + return; +} + +/* TPM_SymmetricKeyData_Load() is DES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* this assumes that DES_cblock is a consistently packed structure. It is in fact an array of 8 + bytes for openSSL. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock1, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock2, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock3, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des3", tpm_symmetric_key_data->des_cblock3); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() DES is non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des3", tpm_symmetric_key_data->des_cblock3); + } + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */s + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store DES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock1, sizeof(DES_cblock)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock2, sizeof(DES_cblock)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock3, sizeof(DES_cblock)); + } + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is DES non-portable code to generate a symmetric key + + vsymmetric_key must be freed by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + DES_random_key(&(tpm_symmetric_key_data->des_cblock1)); + DES_random_key(&(tpm_symmetric_key_data->des_cblock2)); + DES_random_key(&(tpm_symmetric_key_data->des_cblock3)); + /* sets the parity of the passed key to odd. */ + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock1)); + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock2)); + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock3)); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des1", + tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des2", + tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des3", + tpm_symmetric_key_data->des_cblock3); + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is DES non-portable code to encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + unsigned char *decrypt_data_pad; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + if (rc == 0) { + /* calculate the pad length and padded data length */ + pad_length = TPM_DES_BLOCK_SIZE - (decrypt_length % TPM_DES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* encrypt the padded input to the output */ + rc = TPM_SymmetricKeyData_Crypt(*encrypt_data, + decrypt_data_pad, + *encrypt_length, + tpm_symmetric_key_data, + DES_ENCRYPT, + TPM_ENCRYPT_ERROR); + } + free(decrypt_data_pad); /* @1 */ + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is DES non-portable code to decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + uint32_t i; + unsigned char *pad_data; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_DES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + /* decrypt the input to the padded output */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Crypt(*decrypt_data, + encrypt_data, + encrypt_length, + tpm_symmetric_key_data, + DES_DECRYPT, + TPM_DECRYPT_ERROR); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_DES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + return rc; +} + +/* TPM_SymmetricKeyData_Crypt() is DES common code for openSSL, since encrypt and decrypt use the + same function with an 'enc' flag. + + 'data_in' and 'data_out' must be preallocated arrays of 'length' bytes. 'length' must be a + multiple of TPM_DES_BLOCK_SIZE. + + Returns 'error' on error. +*/ + +/* openSSL prototype + + void DES_ede3_cbc_encrypt(const unsigned char *input, + unsigned char *output, long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, DES_cblock *ivec, + int enc); +*/ + +static TPM_RESULT TPM_SymmetricKeyData_Crypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t length, /* input */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, /*in*/ + int enc, /* input */ + TPM_RESULT error) /* input */ +{ + TPM_RESULT rc = 0; + int irc; + DES_key_schedule des_key_schedule1; + DES_key_schedule des_key_schedule2; + DES_key_schedule des_key_schedule3; + DES_cblock ivec; /* initial chaining vector */ + + if (rc == 0) { + if ((length % TPM_DES_BLOCK_SIZE) != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, illegal length %u\n", length); + rc = error; /* should never occur */ + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des3", tpm_symmetric_key_data->des_cblock3); + } + /* Before a DES key can be used, it must be converted into the architecture dependent + DES_key_schedule via the DES_set_key_checked() or DES_set_key_unchecked() function. */ + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock1), &des_key_schedule1); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock2), &des_key_schedule2); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock3), &des_key_schedule3); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + /* initialize initial chaining vector */ + if (rc == 0) { + TPM_PrintFourLimit(" TPM_SymmetricKeyData_Crypt: Input", data_in, length); + /* encrypt operation */ + memset(&ivec, 0, sizeof(DES_cblock)); + DES_ede3_cbc_encrypt(data_in, + data_out, + length, + &des_key_schedule1, + &des_key_schedule2, + &des_key_schedule3, + &ivec, + enc); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: Output", data_out); + } + return rc; +} + +#endif + +#ifdef TPM_AES + +/* TPM_SymmetricKeyData_Init() is AES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + memset(tpm_symmetric_key_data->userKey, 0, sizeof(tpm_symmetric_key_data->userKey)); + memset(&(tpm_symmetric_key_data->aes_enc_key), 0, sizeof(tpm_symmetric_key_data->aes_enc_key)); + memset(&(tpm_symmetric_key_data->aes_dec_key), 0, sizeof(tpm_symmetric_key_data->aes_dec_key)); + return; +} + +/* TPM_SymmetricKeyData_Load() is AES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* The AES key is a simple array. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey), + stream, stream_size); + } + /* reconstruct the internal AES keys */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() is AES non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store AES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_symmetric_key_data->userKey, + sizeof(tpm_symmetric_key_data->userKey)); + } + /* No need to store the internal AES keys. They are reconstructed on load */ + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is AES non-portable code to generate a random symmetric key + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + rc = TPM_Random(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey)); + } + /* construct the internal AES keys */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_SetKey() is AES non-portable code to set a symmetric key from input data + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_SetKey(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + const unsigned char *key_data, + uint32_t key_data_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_SetKey:\n"); + /* check the input data size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (sizeof(tpm_symmetric_key_data->userKey) > key_data_size) { + printf("TPM_SymmetricKeyData_SetKey: Error (fatal), need %lu bytes, received %u\n", + (unsigned long)sizeof(tpm_symmetric_key_data->userKey), key_data_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* copy the input data into the AES key structure */ + memcpy(tpm_symmetric_key_data->userKey, key_data, sizeof(tpm_symmetric_key_data->userKey)); + /* construct the internal AES keys */ + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_SetKeys() is AES non-portable code to construct the internal AES keys from + the userKey + + tpm_symmetric_key_data should be initialized before and after use +*/ + +static TPM_RESULT TPM_SymmetricKeyData_SetKeys(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_SymmetricKeyData_SetKeys:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_SetKeys: userKey", tpm_symmetric_key_data->userKey); + irc = AES_set_encrypt_key(tpm_symmetric_key_data->userKey, + TPM_AES_BITS, + &(tpm_symmetric_key_data->aes_enc_key)); + if (irc != 0) { + printf("TPM_SymmetricKeyData_SetKeys: Error (fatal) generating enc key\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; /* should never occur, null pointers or bad bit size */ + } + } + if (rc == 0) { + irc = AES_set_decrypt_key(tpm_symmetric_key_data->userKey, + TPM_AES_BITS, + &(tpm_symmetric_key_data->aes_dec_key)); + if (irc != 0) { + printf("TPM_SymmetricKeyData_SetKeys: Error (fatal) generating dec key\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; /* should never occur, null pointers or bad bit size */ + } + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is AES non-portable code to encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + unsigned char *decrypt_data_pad; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + if (rc == 0) { + /* calculate the pad length and padded data length */ + pad_length = TPM_AES_BLOCK_SIZE - (decrypt_length % TPM_AES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* encrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Input", decrypt_data_pad); + AES_cbc_encrypt(decrypt_data_pad, + *encrypt_data, + *encrypt_length, + &(tpm_symmetric_key_data->aes_enc_key), + ivec, + AES_ENCRYPT); + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Output", *encrypt_data); + } + free(decrypt_data_pad); /* @1 */ + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is AES non-portable code to decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + uint32_t i; + unsigned char *pad_data; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_AES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + /* decrypt the input to the padded output */ + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* decrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Input", encrypt_data); + AES_cbc_encrypt(encrypt_data, + *decrypt_data, + encrypt_length, + &(tpm_symmetric_key_data->aes_dec_key), + ivec, + AES_DECRYPT); + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Output", *decrypt_data); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_AES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + return rc; +} + +/* TPM_SymmetricKeyData_CtrCrypt() does an encrypt or decrypt (they are the same XOR operation with + a CTR mode pad) of 'data_in' to 'data_out'. + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ctr_in' is the initial CTR value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + const unsigned char *ctr_in, /* input */ + uint32_t ctr_in_size) /* input */ +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = NULL; /* freed @1 */ + unsigned char ctr[TPM_AES_BLOCK_SIZE]; + + printf(" TPM_SymmetricKeyData_CtrCrypt: data_size %u\n", data_size); + /* allocate memory for the key token. The token is opaque in the API, but at this low level, + the code understands the TPM_SYMMETRIC_KEY_DATA structure */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_New((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + } + /* convert the raw key to the AES key, truncating as required */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKey(tpm_symmetric_key_data, + symmetric_key, + symmetric_key_size); + } + /* check the input CTR size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ctr_in_size < sizeof(ctr)) { + printf(" TPM_SymmetricKeyData_CtrCrypt: Error (fatal)" + ", CTR size %u too small for AES key\n", ctr_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of CTR, since AES_ctr128_encrypt alters the value */ + memcpy(ctr, ctr_in, sizeof(ctr)); + printf(" TPM_SymmetricKeyData_CtrCrypt: Calling AES in CTR mode\n"); + TPM_PrintFour(" TPM_SymmetricKeyData_CtrCrypt: CTR", ctr); + rc = TPM_AES_ctr128_encrypt(data_out, + data_in, + data_size, + &(tpm_symmetric_key_data->aes_enc_key), + ctr); + } + TPM_SymmetricKeyData_Free((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); /* @1 */ + return rc; +} + +/* TPM_AES_ctr128_encrypt() is a TPM variant of the openSSL AES_ctr128_encrypt() function that + increments only the low 4 bytes of the counter. + + openSSL increments the entire CTR array. The TPM does not follow that convention. +*/ + +static TPM_RESULT TPM_AES_ctr128_encrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const AES_KEY *aes_enc_key, + unsigned char ctr[TPM_AES_BLOCK_SIZE]) +{ + TPM_RESULT rc = 0; + uint32_t cint; + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + + printf(" TPM_AES_Ctr128_encrypt:\n"); + while (data_size != 0) { + printf(" TPM_AES_Ctr128_encrypt: data_size %lu\n", (unsigned long)data_size); + /* get an XOR pad array by encrypting the CTR with the AES key */ + AES_encrypt(ctr, pad_buffer, aes_enc_key); + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, increment CTR, only the low 4 bytes */ + if (data_size != 0) { + /* CTR is a big endian array, so the low 4 bytes are 12-15 */ + cint = LOAD32(ctr, 12); /* byte array to uint32_t */ + cint++; /* increment */ + STORE32(ctr, 12, cint); /* uint32_t to byte array */ + } + } + return rc; +} + +/* TPM_SymmetricKeyData_OfbCrypt() does an encrypt or decrypt (they are the same XOR operation with + a OFB mode pad) of 'data_in' to 'data_out' + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ivec_in' is the initial IV value before possible truncation +*/ + +/* openSSL prototype + + void AES_ofb128_encrypt(const unsigned char *in, + unsigned char *out, + const unsigned long length, + const AES_KEY *key, + unsigned char *ivec, + int *num); +*/ + +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* in */ + uint32_t symmetric_key_size, /* in */ + unsigned char *ivec_in, /* input */ + uint32_t ivec_in_size) /* input */ +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = NULL; /* freed @1 */ + unsigned char ivec[TPM_AES_BLOCK_SIZE]; + int num; + + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size %u\n", data_size); + /* allocate memory for the key token. The token is opaque in the API, but at this low level, + the code understands the TPM_SYMMETRIC_KEY_DATA structure */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_New((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + } + /* convert the raw key to the AES key, truncating as required */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKey(tpm_symmetric_key_data, + symmetric_key, + symmetric_key_size); + } + /* check the input OFB size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ivec_in_size < sizeof(ivec)) { + printf(" TPM_SymmetricKeyData_OfbCrypt: Error (fatal)," + "IV size %u too small for AES key\n", ivec_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of IV, since AES_ofb128_encrypt alters the value */ + memcpy(ivec, ivec_in, sizeof(ivec)); + num = 0; + printf(" TPM_SymmetricKeyData_OfbCrypt: Calling AES in OFB mode\n"); + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec); + AES_ofb128_encrypt(data_in, + data_out, + data_size, + &(tpm_symmetric_key_data->aes_enc_key), + ivec, + &num); + } + TPM_SymmetricKeyData_Free((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + return rc; +} + +#endif /* TPM_AES */ diff --git a/src/tpm12/tpm_crypto.h b/src/tpm12/tpm_crypto.h new file mode 100644 index 0000000..f2d0701 --- /dev/null +++ b/src/tpm12/tpm_crypto.h @@ -0,0 +1,223 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto.h 4406 2011-02-08 22:11:37Z 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. */ +/********************************************************************************/ + +#ifndef TPM_CRYPTO_H +#define TPM_CRYPTO_H + +#include "config.h" /* libtpms added */ + +#include "tpm_secret.h" +#include "tpm_types.h" + +/* self test */ + +TPM_RESULT TPM_Crypto_Init(void); +TPM_RESULT TPM_Crypto_TestSpecific(void); + +/* random number */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes); +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData); + +/* + bignum +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in); +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in); +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in); +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n); +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, + TPM_BIGNUM aBignum_in, + int n); +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, + TPM_BIGNUM aBignum_in, + int n); +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in); +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in); +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in); +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in); +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in); + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, + const unsigned char *bin, + unsigned int bytes); +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in); + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in); +void TPM_BN_free(TPM_BIGNUM bn_in); + +/* RSA */ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, + unsigned char **p, + unsigned char **q, + unsigned char **d, + int num_bit, + const unsigned char *earr, + uint32_t e_size); + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, + uint32_t *decrypt_data_length, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char* encrypt_data, + uint32_t encrypt_data_size, + unsigned char *n, + uint32_t nbytes, + unsigned char *e, + uint32_t ebytes, + unsigned char *d, + uint32_t dbytes); + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char* encrypt_data, + size_t encrypt_data_size, + TPM_ENC_SCHEME encScheme, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +#if USE_FREEBL_CRYPTO_LIBRARY +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, + uint32_t encrypt_data_size, + unsigned char *decrypt_data, + uint32_t decrypt_data_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +#endif + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr); +TPM_RESULT TPM_RSASign(unsigned char *signature, + unsigned int *signature_length, + unsigned int signature_size, + TPM_SIG_SCHEME sigScheme, + const unsigned char *message, + size_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, + unsigned int signature_size, + const unsigned char *message, + uint32_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +/* SHA-1 */ + +TPM_RESULT TPM_SHA1InitCmd(void **context); +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length); +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context); +void TPM_SHA1Delete(void **context); + +/* SHA-1 Context */ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context); + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data); +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data); +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, + uint32_t *encrypt_length, + const unsigned char *decrypt_data, + uint32_t decrypt_length, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, + uint32_t *decrypt_length, + const unsigned char *encrypt_data, + uint32_t encrypt_length, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + const unsigned char *ctr_in, + uint32_t ctr_in_size); +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *ivec_in, + uint32_t ivec_in_size); +#endif diff --git a/src/tpm12/tpm_crypto_freebl.c b/src/tpm12/tpm_crypto_freebl.c new file mode 100644 index 0000000..272c264 --- /dev/null +++ b/src/tpm12/tpm_crypto_freebl.c @@ -0,0 +1,2652 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto_freebl.c 4655 2011-12-21 21:03:15Z 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. */ +/********************************************************************************/ + +/* This is the FreeBL implementation + + setenv CVSROOT :pserver:anonymous@cvsmirror.mozilla.org:/cvsroot + cvs co mosilla/nsprpub + gmake nss_build_all +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include "blapi.h" +#include <gmp.h> + +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_crypto.h" + +/* The TPM OAEP encoding parameter */ +static const unsigned char tpm_oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + +/* pre-calculate hash of the constant tpm_oaep_pad_str, used often in the OAEP padding + calculations */ +static const unsigned char pHashConst[TPM_DIGEST_SIZE]; + +/* ASN.1 industry standard SHA1 with RSA object identifier */ +static unsigned char sha1Oid[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14}; + + +/* + local prototypes +*/ + +static void TPM_RSAPrivateKeyInit(RSAPrivateKey *rsa_pri_key); +static TPM_RESULT TPM_RSAGeneratePublicToken(RSAPublicKey *rsa_pub_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSAPrivateKey *rsa_pri_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSAPrivateKey *rsa_pri_key); +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSAPrivateKey *rsa_pri_key); + +static TPM_RESULT TPM_RandomNonZero(BYTE *buffer, size_t bytes); + +static TPM_RESULT TPM_PKCS1_PaddingType1Add(unsigned char *output, + uint32_t outputLength, + const unsigned char *input, + uint32_t inputLength); +static TPM_RESULT TPM_PKCS1_PaddingType1Check(uint32_t *padLength, + unsigned char *input, + uint32_t inputLength); +static TPM_RESULT TPM_PKCS1_PaddingType2Add(unsigned char *encodedMessage, + uint32_t encodedMessageLength, + const unsigned char *message, + uint32_t messageLength); +static TPM_RESULT TPM_PKCS1_PaddingType2Check(unsigned char *outputData, + uint32_t *outputDataLength, + uint32_t outputDataSize, + unsigned char *inputData, + uint32_t inputDataLength); + +static TPM_RESULT TPM_memcpyPad(unsigned char **bin_out, + unsigned char *bin_in, + uint32_t bin_in_length, + uint32_t padBytes); + + +/* TPM_SYMMETRIC_KEY_DATA is a crypto library platform dependent symmetric key structure + */ + +#ifdef TPM_AES + +/* local prototype and structure for AES */ + +/* AES requires data lengths that are a multiple of the block size */ +#define TPM_AES_BITS 128 +/* The AES block size is always 16 bytes */ +#define TPM_AES_BLOCK_SIZE 16 + +/* Since the AES key is often derived by truncating the session shared secret, test that it's not + too large +*/ + +#if (TPM_AES_BLOCK_SIZE > TPM_SECRET_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_SECRET_SIZE +#endif + +/* The AES initial CTR value is derived from a nonce. */ + +#if (TPM_AES_BLOCK_SIZE > TPM_NONCE_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_NONCE_SIZE +#endif + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + TPM_BOOL fill; + unsigned char userKey[TPM_AES_BLOCK_SIZE]; +} TPM_SYMMETRIC_KEY_DATA; + +#endif /* TPM_AES */ + +/* + Crypto library Initialization function +*/ + +TPM_RESULT TPM_Crypto_Init() +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf("TPM_Crypto_Init: FreeBL library\n"); + /* initialize the random number generator */ + if (rc == 0) { + printf(" TPM_Crypto_Init: Initializing RNG\n"); + rv = RNG_RNGInit(); + if (rv != SECSuccess) { + printf("TPM_Crypto_Init: Error (fatal), RNG_RNGInit rv %d\n", rv); + rc = TPM_FAIL; + } + } + /* add additional seed entropy to the random number generator */ + if (rc == 0) { + printf(" TPM_Crypto_Init: Seeding RNG\n"); + RNG_SystemInfoForRNG(); + } + if (rc == 0) { + rv = BL_Init(); + if (rv != SECSuccess) { + printf("TPM_Crypto_Init: Error (fatal), BL_Init rv %d\n", rv); + rc =TPM_FAIL ; + } + } + /* pre-calculate hash of the constant tpm_oaep_pad_str, used often in the OAEP padding + calculations */ + if (rc == 0) { + rc = TPM_SHA1((unsigned char *)pHashConst, /* cast once to precalculate the constant */ + sizeof(tpm_oaep_pad_str), tpm_oaep_pad_str, + 0, NULL); + TPM_PrintFour("TPM_Crypto_Init: pHashConst", pHashConst); + } + return rc; +} + +/* TPM_Crypto_TestSpecific() performs any library specific tests + + For FreeBL +*/ + +TPM_RESULT TPM_Crypto_TestSpecific() +{ + TPM_RESULT rc = 0; + + /* Saving the SHA-1 context is fragile code, so test at startup */ + void *context1; + void *context2; + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + int not_equal; + TPM_STORE_BUFFER sbuffer; + const unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Crypto_TestSpecific: Test 1 - SHA1 two parts\n"); + context1 = NULL; /* freed @1 */ + context2 = NULL; /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + + if (rc== 0) { + rc = TPM_SHA1InitCmd(&context1); /* freed @1 */ + } + /* digest the first part of the array */ + if (rc== 0) { + rc = TPM_SHA1UpdateCmd(context1, buffer1, 16); + } + /* store the SHA1 context */ + if (rc== 0) { + rc = TPM_Sha1Context_Store(&sbuffer, context1); + } + /* load the SHA1 context */ + if (rc== 0) { + TPM_Sbuffer_Get(&sbuffer, &stream, &stream_size); + rc = TPM_Sha1Context_Load + (&context2, (unsigned char **)&stream, &stream_size); /* freed @2 */ + } + /* digest the rest of the array */ + if (rc== 0) { + rc = TPM_SHA1UpdateCmd(context2, buffer1 + 16, sizeof(buffer1) - 17); + } + /* get the digest result */ + if (rc== 0) { + rc = TPM_SHA1FinalCmd(actual, context2); + } + /* check the result */ + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_Crypto_TestSpecific: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + TPM_SHA1Delete(&context1); /* @1 */ + TPM_SHA1Delete(&context2); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rc; +} + +/* + Random Number Functions +*/ + +/* TPM_Random() fills 'buffer' with 'bytes' bytes. + */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_Random: Requesting %lu bytes\n", (unsigned long)bytes); + /* generate the random bytes */ + if (rc == 0) { + rv = RNG_GenerateGlobalRandomBytes(buffer, bytes); + if (rv != SECSuccess) { + printf("TPM_Random: Error (fatal) in RNG_GenerateGlobalRandomBytes rv %d\n", rv); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_Random() fills 'buffer' with 'bytes' non-zero bytes + + This is used for PKCS padding. +*/ + +static TPM_RESULT TPM_RandomNonZero(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + size_t i; + SECStatus rv = SECSuccess; + + printf(" TPM_RandomNonZero: Requesting %lu bytes\n", (unsigned long)bytes); + for (i = 0 ; (rc == 0) && (i < bytes) ; ) { + rv = RNG_GenerateGlobalRandomBytes(buffer, 1); + if (rv != SECSuccess) { + printf("TPM_Random: Error (fatal) in RNG_GenerateGlobalRandomBytes rv %d\n", rv); + rc = TPM_FAIL; + } + else { + if (*buffer != 0x00) { + buffer++; + i++; + } + } + } + return rc; +} + +/* TPM_StirRandomCmd() adds the supplied entropy to the random number generator + */ + +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_StirRandomCmd:\n"); + if (rc == 0) { + /* add the seeding material */ + rv = RNG_RandomUpdate(inData->buffer, inData->size); + if (rv != SECSuccess) { + printf("TPM_StirRandom: Error (fatal) in RNG_RandomUpdate rv %d\n", rv); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + RSA Functions +*/ + +/* TPM_RSAPrivateKeyInit() NULLs all the structure members in preparation for constructing an RSA + key token from byte arrays using RSA_PopulatePrivateKey() +*/ + +static void TPM_RSAPrivateKeyInit(RSAPrivateKey *rsa_pri_key) +{ + rsa_pri_key->arena = NULL; + rsa_pri_key->publicExponent.type = siBuffer; + rsa_pri_key->publicExponent.data = NULL; + rsa_pri_key->publicExponent.len = 0; + rsa_pri_key->modulus.type = siBuffer; + rsa_pri_key->modulus.data = NULL; + rsa_pri_key->modulus.len = 0; + rsa_pri_key->privateExponent.type = siBuffer; + rsa_pri_key->privateExponent.data = NULL; + rsa_pri_key->privateExponent.len = 0; + rsa_pri_key->prime1.type = siBuffer; + rsa_pri_key->prime1.data = NULL; + rsa_pri_key->prime1.len = 0; + rsa_pri_key->prime2.type = siBuffer; + rsa_pri_key->prime2.data = NULL; + rsa_pri_key->prime2.len = 0; + rsa_pri_key->exponent1.type = siBuffer; + rsa_pri_key->exponent1.data = NULL; + rsa_pri_key->exponent1.len = 0; + rsa_pri_key->exponent2.type = siBuffer; + rsa_pri_key->exponent2.data = NULL; + rsa_pri_key->exponent2.len = 0; + rsa_pri_key->coefficient.type = siBuffer; + rsa_pri_key->coefficient.data = NULL; + rsa_pri_key->coefficient.len = 0; + return; +} + +/* Generate an RSA key pair of size 'num_bits' using public exponent 'earr' + + 'n', 'p', 'q', 'd' must be freed by the caller +*/ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, /* public key - modulus */ + unsigned char **p, /* private key prime */ + unsigned char **q, /* private key prime */ + unsigned char **d, /* private key (private exponent) */ + int num_bits, /* key size in bits */ + const unsigned char *earr, /* public exponent as an array */ + uint32_t e_size) +{ + TPM_RESULT rc = 0; + SECItem publicExponent = { 0, 0, 0}; + RSAPrivateKey *rsaPrivateKey = NULL; /* freed @1 */ + unsigned long e; /* public exponent */ + + printf(" TPM_RSAGenerateKeyPair:\n"); + /* initialize in case of error */ + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + /* check that num_bits is a multiple of 16. If not, the primes p and q will not be a multiple + of 8 and will not fit well in a byte */ + if (rc == 0) { + if ((num_bits % 16) != 0) { + printf("TPM_RSAGenerateKeyPair: Error, num_bits %d is not a multiple of 16\n", + num_bits); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* convert the e array to an unsigned long */ + if (rc == 0) { + rc = TPM_LoadLong(&e, earr, e_size); + } + /* validate the public exponent against a list of legal values. Some values (e.g. even numbers) + can hang the key generator. */ + if (rc == 0) { + rc = TPM_RSA_exponent_verify(e); + } + /* generate the key pair */ + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: num_bits %d exponent %08lx\n", num_bits, e); + publicExponent.type = siBuffer; + publicExponent.data = (unsigned char *)earr; + publicExponent.len = e_size; + /* Generate and return a new RSA public and private key token */ + rsaPrivateKey = RSA_NewKey(num_bits, &publicExponent); /* freed @1 */ + if (rsaPrivateKey == NULL) { + printf("TPM_RSAGenerateKeyPair: Error (fatal) calling RSA_NewKey()\n"); + rc = TPM_FAIL; + } + } + /* Key parts can some times have leading zeros, and some crypto libraries truncate. However, + the TPM expects fixed lengths. These calls restore any removed padding */ + /* load n */ + if (rc == 0) { + rc = TPM_memcpyPad(n, /* freed by caller */ + rsaPrivateKey->modulus.data, + rsaPrivateKey->modulus.len, + num_bits/8); /* required length */ + } + /* load p */ + if (rc == 0) { + rc = TPM_memcpyPad(p, /* freed by caller */ + rsaPrivateKey->prime1.data, + rsaPrivateKey->prime1.len, + num_bits/16); /* required length */ + } + /* load q */ + if (rc == 0) { + rc = TPM_memcpyPad(q, /* freed by caller */ + rsaPrivateKey->prime2.data, + rsaPrivateKey->prime2.len, + num_bits/16); /* required length */ + } + /* load d */ + if (rc == 0) { + rc = TPM_memcpyPad(d, /* freed by caller */ + rsaPrivateKey->privateExponent.data, + rsaPrivateKey->privateExponent.len, + num_bits/8); /* required length */ + } + /* on error, free the components and set back to NULL so subsequent free is safe */ + if (rc != 0) { + free(*n); + free(*p); + free(*q); + free(*d); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + } + if (rsaPrivateKey != NULL) { + PORT_FreeArena(rsaPrivateKey->arena, PR_TRUE); /* @1 */ + } + return rc; +} + +/* TPM_RSAGeneratePublicToken() generates an RSA key token from n and e + */ + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSAPublicKey *rsaPublicKey, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + + /* simply assign the arrays to the key token */ + if (rc == 0) { + printf(" TPM_RSAGeneratePublicToken: nbytes %u ebytes %u\n", nbytes, ebytes); + rsaPublicKey->arena = NULL; + /* public modulus */ + rsaPublicKey->modulus.type = siBuffer; + rsaPublicKey->modulus.data = narr; + rsaPublicKey->modulus.len = nbytes; + /* public exponent */ + rsaPublicKey->publicExponent.type = siBuffer; + rsaPublicKey->publicExponent.data = earr; + rsaPublicKey->publicExponent.len = ebytes; + } + return rc; +} + +/* TPM_RSAGeneratePrivateToken() generates an RSA key token from n, e, d + */ + +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSAPrivateKey *rsa_pri_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_RSAGeneratePrivateToken:\n"); + if (rc == 0) { + rsa_pri_key->arena = NULL; + /* public exponent */ + rsa_pri_key->publicExponent.type = siBuffer; + rsa_pri_key->publicExponent.data = earr; + rsa_pri_key->publicExponent.len = ebytes; + /* public modulus */ + rsa_pri_key->modulus.type = siBuffer; + rsa_pri_key->modulus.data = narr; + rsa_pri_key->modulus.len = nbytes; + /* private exponent */ + rsa_pri_key->privateExponent.type = siBuffer; + rsa_pri_key->privateExponent.data = darr; + rsa_pri_key->privateExponent.len = dbytes; + /* given these key parameters (n,e,d), fill in the rest of the parameters */ + rv = RSA_PopulatePrivateKey(rsa_pri_key); /* freed by caller */ + if (rv != SECSuccess) { + printf("TPM_RSAGeneratePrivateToken: Error, RSA_PopulatePrivateKey rv %d\n", rv); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_RSAPrivateDecrypt() decrypts 'encrypt_data' using the private key 'n, e, d'. The OAEP + padding is removed and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + size_t decrypt_data_size, /* size of decrypt_data buffer */ + TPM_ENC_SCHEME encScheme, /* encryption scheme */ + unsigned char* encrypt_data, /* encrypted data */ + uint32_t encrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPrivateKey rsa_pri_key; + unsigned char *padded_data = NULL; /* freed @2 */ + int padded_data_size = 0; + + printf(" TPM_RSAPrivateDecrypt: Input data size %u\n", encrypt_data_size); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + /* the encrypted data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPrivateDecrypt: Error, Encrypted data size is %u not %u\n", + encrypt_data_size, nbytes); + rc = TPM_DECRYPT_ERROR; + } + } + /* construct the freebl private key object from n,e,d */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* allocate intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + /* the size of the decrypted data is guaranteed to be less than this */ + padded_data_size = rsa_pri_key.modulus.len; + rc = TPM_Malloc(&padded_data, padded_data_size); /* freed @2 */ + } + if (rc == 0) { + /* decrypt with private key. Must decrypt first and then remove padding because the decrypt + call cannot specify an encoding parameter */ + rv = RSA_PrivateKeyOp(&rsa_pri_key, /* private key token */ + padded_data, /* to - the decrypted but padded data */ + encrypt_data); /* from - the encrypted data */ + if (rv != SECSuccess) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_PrivateKeyOp(), rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_PrivateKeyOp() success\n"); + printf(" TPM_RSAPrivateDecrypt: Padded data size %u\n", padded_data_size); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt padded data", padded_data); + /* check and remove the padding based on the TPM encryption scheme */ + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + /* recovered seed and pHash are not returned */ + unsigned char seed[TPM_DIGEST_SIZE]; + unsigned char pHash[TPM_DIGEST_SIZE]; + if (rc == 0) { + /* the padded data skips the first 0x00 byte, since it expects the + padded data to come from a truncated bignum */ + rc = TPM_RSA_padding_check_PKCS1_OAEP(decrypt_data, /* to */ + decrypt_data_length, /* to length */ + decrypt_data_size, /* to buffer size */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + pHash, /* 20 bytes */ + seed); /* 20 bytes */ + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + rc = TPM_PKCS1_PaddingType2Check(decrypt_data, /* to */ + decrypt_data_length, /* to length */ + decrypt_data_size, /* to buffer size*/ + padded_data, /* from */ + padded_data_size); /* from length */ + } + else { + printf("TPM_RSAPrivateDecrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_padding_check_PKCS1 recovered %d bytes\n", + *decrypt_data_length); + TPM_PrintFourLimit(" TPM_RSAPrivateDecrypt: Decrypt data", decrypt_data, decrypt_data_size); + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + free(padded_data); /* @2 */ + return rc; +} + +/* TPM_RSAPublicEncrypt() PKCS1 pads 'decrypt_data' to 'encrypt_data_size' and encrypts using the + public key 'n, e'. +*/ + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char *encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + TPM_ENC_SCHEME encScheme, /* padding type */ + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + unsigned char *padded_data = NULL; /* freed @1 */ + + printf(" TPM_RSAPublicEncrypt: Input data size %lu\n", (unsigned long)decrypt_data_size); + /* intermediate buffer for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, encrypt_data_size); /* freed @1 */ + } + /* pad the decrypted data */ + if (rc == 0) { + /* based on the TPM encryption scheme */ + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + unsigned char seed[TPM_DIGEST_SIZE]; + if (rc == 0) { + rc = TPM_Random(seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + padded_data[0] = 0x00; + rc = TPM_RSA_padding_add_PKCS1_OAEP(padded_data +1, /* to */ + encrypt_data_size -1, /* to length */ + decrypt_data, /* from */ + decrypt_data_size, /* from length */ + pHashConst, /* 20 bytes */ + seed); /* 20 bytes */ + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + rc = TPM_PKCS1_PaddingType2Add(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size); /* from length */ + } + else { + printf("TPM_RSAPublicEncrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + /* raw public key operation on the already padded input data */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptRaw(encrypt_data, /* output */ + encrypt_data_size, /* input, size of enc buffer */ + padded_data, /* input */ + encrypt_data_size, /* input, size of dec buffer */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + free(padded_data); /* @1 */ + return rc; +} + +/* TPM_RSAPublicEncryptRaw() does a raw public key operation without any padding. + +*/ + +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, /* output */ + uint32_t encrypt_data_size, /* input, size of enc buffer */ + unsigned char *decrypt_data, /* input */ + uint32_t decrypt_data_size, /* input, size of dec buffer */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPublicKey rsa_pub_key; + + printf(" TPM_RSAPublicEncryptRaw:\n"); + /* the input data size must equal the public key size (already padded) */ + if (rc == 0) { + if (decrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, decrypt data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* the output data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, Output data size is %u not %u\n", + encrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* construct the freebl public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freebl public key token */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Public modulus", narr); + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Public exponent", earr, ebytes); + TPM_PrintFourLimit(" TPM_RSAPublicEncryptRaw: Decrypt data", decrypt_data, decrypt_data_size); + /* raw public key operation, encrypt the decrypt_data */ + rv = RSA_PublicKeyOp(&rsa_pub_key, /* freebl public key token */ + encrypt_data, /* output - the encrypted data */ + decrypt_data); /* input - the clear text data */ + if (rv != SECSuccess) { + printf("TPM_RSAPublicEncrypt: Error in RSA_PublicKeyOp, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Encrypt data", encrypt_data); +#if 0 /* NOTE: Uncomment as a debug aid for signature verification */ + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Encrypt data", + encrypt_data, encrypt_data_size); +#endif + } + return rc; +} + +/* TPM_RSASign() signs 'message' of size 'message_size' using the private key n,e,d and the + signature scheme 'sigScheme' as specified in PKCS #1 v2.0. + + 'signature_length' bytes are moved to 'signature'. 'signature_length' is at most + 'signature_size'. signature must point to bytes of memory equal to the public modulus size. +*/ + +TPM_RESULT TPM_RSASign(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + RSAPrivateKey rsa_pri_key; + + printf(" TPM_RSASign:\n"); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + /* construct the free private key object from n,e,d */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* sanity check the size of the output signature buffer */ + if (rc == 0) { + if (signature_size < nbytes) { + printf("TPM_RSASign: Error (fatal), buffer %u too small for signature %u\n", + signature_size, nbytes); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSASign: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSASignSHA1(signature, + signature_length, + message, + message_size, + &rsa_pri_key); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + rc = TPM_RSASignDER(signature, + signature_length, + message, + message_size, + &rsa_pri_key); + break; + default: + printf("TPM_RSASign: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + return rc; +} + +/* TPM_RSASignSHA1() performs the following: + prepend a DER encoded algorithm ID (SHA1 and RSA) + prepend a type 1 pad + encrypt with the private key +*/ + +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSAPrivateKey *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + unsigned char *message_der; /* DER padded message, freed @1 */ + + printf(" TPM_RSASignSHA1: key size %d\n", rsa_pri_key->modulus.len); + message_der = NULL; /* freed @1 */ + /* sanity check, SHA1 messages must be 20 bytes */ + if (rc == 0) { + if (message_size != TPM_DIGEST_SIZE) { + printf("TPM_RSASignSHA1: Error, message size %lu not TPM_DIGEST_SIZE\n", + (unsigned long)message_size ); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the DER padded message */ + if (rc == 0) { + rc = TPM_Malloc(&message_der, sizeof(sha1Oid) + message_size); /* freed @1 */ + } + if (rc == 0) { + /* copy the OID */ + memcpy(message_der, sha1Oid, sizeof(sha1Oid)); + /* copy the message */ + memcpy(message_der + sizeof(sha1Oid), message, message_size); + /* sign the DER padded message */ + rc = TPM_RSASignDER(signature, /* output */ + signature_length, /* output, size of signature */ + message_der, /* input */ + sizeof(sha1Oid) + message_size, /* input */ + rsa_pri_key); /* signing private key */ + } + free(message_der); /* @1 */ + return rc; +} + +/* TPM_RSASignDER() performs the following: + + prepend a PKCS1 type 1 pad + encrypt with the private key + + The caller must ensure that the signature buffer is >= the key size. +*/ + +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSAPrivateKey *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + unsigned char *message_pad; /* PKCS1 type 1 padded message, freed @1 */ + + printf(" TPM_RSASignDER: key size %d\n", rsa_pri_key->modulus.len); + message_pad = NULL; /* freed @1 */ + /* the padded message size is the same as the key size */ + /* allocate memory for the padded message */ + if (rc == 0) { + rc = TPM_Malloc(&message_pad, rsa_pri_key->modulus.len); /* freed @1 */ + } + /* PKCS1 type 1 pad the message */ + if (rc == 0) { + printf(" TPM_RSASignDER: Applying PKCS1 type 1 padding, size from %lu to %u\n", + (unsigned long)message_size, rsa_pri_key->modulus.len); + TPM_PrintFourLimit(" TPM_RSASignDER: Input message", message, message_size); + /* This call checks that the message will fit with the padding */ + rc = TPM_PKCS1_PaddingType1Add(message_pad, /* to */ + rsa_pri_key->modulus.len, /* to length */ + message, /* from */ + message_size); /* from length */ + } + /* raw sign with private key */ + if (rc == 0) { + printf(" TPM_RSASignDER: Encrypting with private key, message size %d\n", + rsa_pri_key->modulus.len); + TPM_PrintFour(" TPM_RSASignDER: Padded message", message_pad); + /* sign with private key */ + rv = RSA_PrivateKeyOp(rsa_pri_key, /* freebl key token */ + signature, /* to - the decrypted but padded data */ + message_pad); /* from - the encrypted data */ + if (rv != SECSuccess) { + printf("TPM_RSASignDER: Error in RSA_PrivateKeyOp(), rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignDER: signature", signature); + *signature_length = rsa_pri_key->modulus.len; + } + free(message_pad); /* @1 */ + return rc; +} + +/* TPM_RSAVerifySHA1() performs the following: + decrypt the signature + verify and remove type 1 pad + verify and remove DER encoded algorithm ID + verify the signature on the message +*/ + +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature + buffer */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + unsigned char *padded_data = NULL; /* decrypted signature, freed @1 */ + uint32_t padLength; + int irc; + + printf(" TPM_RSAVerifySHA1:\n"); + /* allocate memory for the padded result of the public key operation */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, nbytes); /* freed @1 */ + } + /* do a raw encrypt of the signature */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptRaw(padded_data, /* output */ + nbytes, /* input, size of message buffer */ + signature, /* input */ + signature_size, /* input, size of signature buffer */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + /* check PKCS1 padding and OID */ + if (rc == 0) { + rc = TPM_PKCS1_PaddingType1Check(&padLength, /* length of the PKCS1 padd and OID */ + padded_data, /* input data */ + nbytes); /* input data length */ + } + /* check message length */ + if (rc == 0) { + if (message_size != (nbytes - padLength)) { + printf("TPM_RSAVerifySHA1: Error, " + "message size %u not equal to size %u after padding removed\n", + message_size, nbytes - padLength); + rc = TPM_BAD_SIGNATURE; + } + } + /* check message */ + if (rc == 0) { + irc = memcmp(message, padded_data + padLength, message_size); + if (irc != 0) { + printf("TPM_RSAVerifySHA1: Error, message mismatch\n"); + TPM_PrintFourLimit(" TPM_RSAVerifySHA1: message", message, message_size); + TPM_PrintFourLimit(" TPM_RSAVerifySHA1: message from signature", padded_data + padLength, message_size); + rc = TPM_BAD_SIGNATURE; + } + } + /* public encrypt is general, here we're doing a signature check, so adjust the error message */ + else { + rc = TPM_BAD_SIGNATURE; + } + free(padded_data); /* @1 */ + return rc; +} + +/* TPM_RSAGetPrivateKey calculates q (2nd prime factor) and d (private key) from n (public key), e + (public exponent), and p (1st prime factor) + + 'qarr', darr' must be freed by the caller. +*/ + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPrivateKey rsa_pri_key; + + /* set to NULL so caller can free after failure */ + printf(" TPM_RSAGetPrivateKey:\n"); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + *qarr = NULL; + *darr = NULL; + /* check input parameters */ + if (rc == 0) { + if ((narr == NULL) || (nbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing n\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((earr == NULL) || (ebytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing e\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((parr == NULL) || (pbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing p\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* populate the private key token with n, e, p */ + if (rc == 0) { + rsa_pri_key.publicExponent.type = siBuffer; + rsa_pri_key.publicExponent.data = earr; + rsa_pri_key.publicExponent.len = ebytes; + rsa_pri_key.modulus.type = siBuffer; + rsa_pri_key.modulus.data = narr; + rsa_pri_key.modulus.len = nbytes; + rsa_pri_key.prime1.type = siBuffer; + rsa_pri_key.prime1.data = parr; + rsa_pri_key.prime1.len = pbytes; + /* fill in the rest of the freebl key token parameters. */ + rv = RSA_PopulatePrivateKey(&rsa_pri_key); /* freed @1 */ + if (rv != SECSuccess) { + printf("TPM_RSAGetPrivateKey: Error in RSA_PopulatePrivateKey rv %d\n", rv); + rc = TPM_BAD_PARAMETER; + } + } + /* extract and pad q */ + if (rc == 0) { + rc = TPM_memcpyPad(qarr, /* freed by caller */ + rsa_pri_key.prime2.data, rsa_pri_key.prime2.len, + pbytes); /* pad to p prime */ + *qbytes = pbytes; + } + /* extract and pad d */ + if (rc == 0) { + rc = TPM_memcpyPad(darr, /* freed by caller */ + rsa_pri_key.privateExponent.data, rsa_pri_key.privateExponent.len, + nbytes); /* pad to public modulus */ + *dbytes = nbytes; + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated q", *qarr); + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated d", *darr); + printf(" TPM_RSAGetPrivateKey: length of n,p,q,d = %u / %u / %u / %u\n", + nbytes, pbytes, *qbytes, *dbytes); + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + return rc; +} + +/* + PKCS1 Padding Functions +*/ + +/* TPM_PKCS1_PaddingType1Add() adds PKCS1 type 1 padding. + + The output buffer is preallocated. +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType1Add(unsigned char *output, /* to */ + uint32_t outputLength, + const unsigned char *input, /* from */ + uint32_t inputLength) +{ + TPM_RESULT rc = 0; + uint32_t psLength; + uint32_t index; + + /* sanity check the length, this should never fail */ + printf(" TPM_PKCS1_PaddingType1Add:\n"); + if (rc == 0) { + if ((inputLength + 11) > outputLength) { + printf("TPM_PKCS1_PaddingType1Add: Error, input %u too big for output %u\n", + inputLength, outputLength); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + index = 0; + /* psLength is the number of 0xff bytes, subtract 3 for the leading 00,01 and trailing 00 */ + psLength = outputLength - inputLength - 3; + + /* add the PKCS1 pad 01 || PS || 00 || T where PS is at least 8 0xff bytes */ + /* PKCS1 pads to k-1 bytes, implies a leading 0 */ + output[index] = 0x00; + index++; + + output[index] = 0x01; + index++; + + memset(output + index, 0xff, psLength); + index += psLength; + + output[index] = 0x00; + index++; + + /* add the input data */ + memcpy(output + index, input, inputLength); + index += inputLength; + } + return rc; +} + +/* TPM_PKCS1_PaddingType1Check() checks PKCS1 type 1 padding and the SHA1withRSA OID + and returns their length + + Type 1 is: 00 01 FF's 00 OID message +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType1Check(uint32_t *padLength, + unsigned char *input, + uint32_t inputLength) +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_PKCS1_PaddingType1Check:\n"); + /* sanity check the length */ + if (rc == 0) { + if ((sizeof(sha1Oid) + 11) > inputLength) { + printf("TPM_PKCS1_PaddingType1Check: Error, " + "sizeof(sha1Oid) %lu + 11 > inputLength %u\n", + (unsigned long)sizeof(sha1Oid), inputLength); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check byte 0 */ + if (rc == 0) { + *padLength = 0; + if (input[*padLength] != 0x00) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x00\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check byte 1 */ + if (rc == 0) { + if (input[*padLength] != 0x01) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x01\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check for at least 8 0xff bytes */ + for ( ; (rc == 0) && (*padLength < 10) ; (*padLength)++) { + if (input[*padLength] != 0xff) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0xff\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check for more 0xff bytes */ + for ( ; (rc == 0) && (*padLength < inputLength) ; (*padLength)++) { + if (input[*padLength] != 0xff) { + break; + } + } + /* check for 0x00 byte */ + if (rc == 0) { + if (input[*padLength] != 0x00) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x00\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check length for OID */ + if (rc == 0) { + if (*padLength + sizeof(sha1Oid) > inputLength) { + printf("TPM_PKCS1_PaddingType1Check: Error, " + "padLength %u + sizeof(sha1Oid) %lu > inputLength %u\n", + *padLength, (unsigned long)sizeof(sha1Oid), inputLength); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check OID */ + if (rc == 0) { + irc = memcmp(input + *padLength, sha1Oid, sizeof(sha1Oid)); + if (irc != 0) { + printf("TPM_PKCS1_PaddingType1Check: Error, OID mismatch\n"); + TPM_PrintAll(" TPM_PKCS1_PaddingType1Check: OID", + input + *padLength, sizeof(sha1Oid)); + rc = TPM_ENCRYPT_ERROR; + } + *padLength += sizeof(sha1Oid); + } + return rc; +} + +/* TPM_PKCS1_PaddingType2Add() adds the PKCS1 type 2 padding + + The output buffer is preallocated. + + See PKCS1 9.1.2.1 Encoding operation + + This method cheats a bit by adding a leading 00 as well, which is needed for the RSA operation. + + M message to be encoded, an octet string of length at most emLen-10 + emLen intended length in octets of the encoded message + + Output: + EM encoded message, an octet string of length emLen; or "message too long" +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType2Add(unsigned char *encodedMessage, /* to */ + uint32_t encodedMessageLength, /* to length */ + const unsigned char *message, /* from */ + uint32_t messageLength) /* from length */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PKCS1_PaddingType2Add: Message length %u padded length %u\n", + messageLength, encodedMessageLength); + /* 1. If the length of the message M is greater than emLen - 10 octets, output "message too + long" and stop. */ + if (rc == 0) { + if ((messageLength + 11) > encodedMessageLength) { + printf("TPM_PKCS1_PaddingType2Add: Error, message length too big for padded length\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* 2. Generate an octet string PS of length emLen-||M||-2 consisting of pseudorandomly generated + nonzero octets. The length of PS will be at least 8 octets. */ + if (rc == 0) { + rc = TPM_RandomNonZero(encodedMessage + 2, encodedMessageLength - messageLength - 3); + } + /* 3. Concatenate PS, the message M, and other padding to form the encoded message EM as: */ + /* EM = 02 || PS || 00 || M */ + if (rc == 0) { + encodedMessage[0] = 0x00; + encodedMessage[1] = 0x02; + encodedMessage[encodedMessageLength - messageLength - 1] = 0x00; + memcpy(encodedMessage + encodedMessageLength - messageLength, message, messageLength); + } + return rc; +} + +/* TPM_PKCS1_Type2PaddingCheck checks the PKCS1 type 2 padding and recovers the message + + The output buffer is preallocated. +*/ + +static +TPM_RESULT TPM_PKCS1_PaddingType2Check(unsigned char *outputData, /* to */ + uint32_t *outputDataLength, /* to length */ + uint32_t outputDataSize, /* pre-allocated to length */ + unsigned char *inputData, /* from - padded data */ + uint32_t inputDataLength) /* from length */ +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PKCS1_PaddingType2Check:\n"); + /* check the leading bytes for 0x00, 0x02 */ + if (rc == 0) { + if ((inputData[0] != 0x00) || + (inputData[1] != 0x02)) { + printf("TPM_PKCS1_PaddingType2Check: Error, bad leading bytes %02x %02x\n", + inputData[0], inputData[1]); + rc = TPM_DECRYPT_ERROR; + } + } + /* skip the non-zero random PS */ + for (i = 2 ; (rc == 0) && (i < inputDataLength) ; i++) { + if (inputData[i] == 0x00) { + break; + } + } + /* check for the trailing 0x00 */ + if (rc == 0) { + if (i == inputDataLength) { + printf("TPM_PKCS1_PaddingType2Check: Error, missing trailing 0x00\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* check that PS was at least 8 bytes */ + if (rc == 0) { + if (i < 10) { + printf("TPM_PKCS1_PaddingType2Check: Error, bad PS length %lu\n", (unsigned long)i-2); + rc = TPM_DECRYPT_ERROR; + } + } + /* check that the output can accommodate the message */ + if (rc == 0) { + i++; /* index past the trailing 0x00 */ + *outputDataLength = inputDataLength - i; + if (*outputDataLength > outputDataSize) { + printf("TPM_PKCS1_PaddingType2Check: Error, " + "message %u greater than output data size %u\n", + *outputDataLength, outputDataSize); + rc = TPM_DECRYPT_ERROR; + } + } + /* copy the message */ + if (rc == 0) { + memcpy(outputData, inputData + inputDataLength - *outputDataLength, *outputDataLength); + } + return rc; +} + +/* + GNU MP wrappers do error logging and transformation of errors to TPM type errors +*/ + +/* TPM_BN_num_bytes() wraps the gnump function in a TPM error handler + + Returns number of bytes in the input +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + + /* is the bignum zero */ + int result = mpz_cmp_ui(*bn, 0); + /* mpz_sizeinbase() always returns at least one. If the value is zero, there should really be 0 + bytes */ + if (result == 0) { + *numBytes = 0; + } + /* take the base 2 number and round up to the next byte */ + else { + *numBytes = (mpz_sizeinbase (*bn, 2) +7) / 8; + } + return rc; +} + +/* TPM_BN_is_one() wraps the gnump function in a TPM error handler + + Returns success if input is 1 +*/ + +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + int irc; + + irc = mpz_cmp_ui(*bn, 1); + if (irc != 0) { + printf("TPM_BN_is_one: Error, result is not 1\n"); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + + +/* TPM_BN_mod() wraps the gnump function in a TPM error handler + + r = a mod m +*/ + +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rem_in; + mpz_t *aBignum = (mpz_t *)a_in; + mpz_t *mBignum = (mpz_t *)m_in; + + /* set r to a mod m */ + mpz_mod(*rBignum, *aBignum, *mBignum); + return rc; +} + +/* TPM_BN_mask_bits() wraps the gnump function in a TPM error handler + + erase all but the lowest n bits of bn + bn = bn mod 2^^n +*/ + +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n) +{ + TPM_RESULT rc = 0; + unsigned int numBytes; + mpz_t *bn = (mpz_t *)bn_in; + + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, bn_in); + } + if (rc == 0) { + /* if the BIGNUM is already fewer bits, no need to mask */ + if (numBytes > (n / 8)) { + /* divide and return remainder, divisor is 2^^n */ + mpz_fdiv_r_2exp(*bn, *bn, n); + } + } + return rc; +} + +/* TPM_BN_rshift() wraps the gnump function in a TPM error handler + + Shift a right by n bits (discard the lowest n bits) and label the result r +*/ + +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + mpz_t **rBignum = (mpz_t **)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + + printf(" TPM_BN_rshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* divide and return quotient, rounded down (floor) */ + mpz_fdiv_q_2exp(**rBignum, *aBignum, n); + } + return rc; +} + +/* TPM_BN_lshift() wraps the gnump function in a TPM error handler + + Shift a left by n bits and label the result r +*/ + +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + mpz_t **rBignum = (mpz_t **)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + + printf(" TPM_BN_lshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* multiply by 2^^n is is a left shift by n */ + mpz_mul_2exp(**rBignum, *aBignum, n); + } + return rc; +} + +/* TPM_BN_add() wraps the gnump function in a TPM error handler + + r = a + b +*/ + +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + + printf(" TPM_BN_add:\n"); + /* result = a + b */ + mpz_add(*rBignum, *aBignum, *bBignum); + return rc; +} + +/* TPM_BN_mul() wraps the gnump function in a TPM error handler + + r = a * b +*/ + +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + + printf(" TPM_BN_mul:\n"); + /* r = a * b */ + mpz_mul(*rBignum, *aBignum, *bBignum); + return rc; +} + +/* TPM_BN_mod_exp() wraps the gnump function in a TPM error handler + + computes a to the p-th power modulo m (r=a^p % n) +*/ + +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *pBignum = (mpz_t *)pBignum_in; + mpz_t *nBignum = (mpz_t *)nBignum_in; + + printf(" TPM_BN_mod_exp:\n"); + mpz_powm(*rBignum, *aBignum, *pBignum, *nBignum); + return rc; +} + +/* TPM_BN_Mod_add() wraps the gnump function in a TPM error handler + + adds a to b modulo m +*/ + +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + mpz_t *mBignum = (mpz_t *)mBignum_in; + + printf(" TPM_BN_mod_add:\n"); + /* r = a + b */ + mpz_add(*rBignum, *aBignum, *bBignum); + /* set r to r mod m */ + mpz_mod(*rBignum, *rBignum, *mBignum); + return rc; +} + +/* TPM_BN_mod_mul() wraps the gnump function in a TPM error handler + + r = (a * b) mod m +*/ + +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + mpz_t *mBignum = (mpz_t *)mBignum_in; + + printf(" TPM_BN_mod_mul:\n"); + /* r = a * b */ + mpz_mul(*rBignum, *aBignum, *bBignum); + /* set r to r mod m */ + mpz_mod(*rBignum, *rBignum, *mBignum); + return rc; +} + +/* TPM_BN_new() wraps the gnump function in a TPM error handler + + Allocates a new bignum +*/ + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in) /* freed by caller */ +{ + TPM_RESULT rc = 0; + mpz_t *bn; + + if (rc== 0) { + rc = TPM_Malloc(bn_in, sizeof(mpz_t)); /* freed by caller */ + } + if (rc== 0) { + bn = (mpz_t *)*bn_in; + mpz_init(*bn); + } + return rc; +} + +/* TPM_BN_free() wraps the gnump function + + Frees the bignum +*/ + +void TPM_BN_free(TPM_BIGNUM bn_in) +{ + mpz_t *bn = (mpz_t *)bn_in; + if (bn != NULL) { + mpz_clear(*bn); + free(bn_in); + } + return; +} + +/* TPM_bn2bin wraps the function in gnump a TPM error handler. + + Converts a bignum to char array + + 'bin' must already be checked for sufficient size. +*/ + +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + + mpz_export(bin, /* output */ + NULL, /* countp */ + 1, /* order, MSB first */ + 1, /* size, char */ + 0, /* endian, native (unused) */ + 0, /* nails, don't discard */ + *bn); /* input */ + return rc; +} + +/* TPM_memcpyPad allocates a buffer 'bin_out' and loads it from 'bin_in'. + + If padBytes is non-zero, 'bin_out' is padded with leading zeros if necessary, so that 'bytes' + will equal 'padBytes'. This is used when TPM data structures expect a fixed length while + the crypto library truncates leading zeros. + + '*bin_out' must be freed by the caller +*/ + +static TPM_RESULT TPM_memcpyPad(unsigned char **bin_out, + unsigned char *bin_in, + uint32_t bin_in_length, + uint32_t padBytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_memcpyPad: padBytes %u\n", padBytes); + if (rc == 0) { + /* padBytes 0 says that no padding is required */ + if (padBytes == 0) { + padBytes = bin_in_length; /* setting equal yields no padding */ + } + /* The required output should never be less than the supplied input. Sanity check and + return a fatal error. */ + if (padBytes < bin_in_length) { + printf("TPM_memcpyPad: Error (fatal), " + "padBytes %u less than %u\n", padBytes, bin_in_length); + rc = TPM_FAIL; + } + if (padBytes != bin_in_length) { + printf(" TPM_memcpyPad: padBytes %u bytes %u\n", padBytes, bin_in_length); + } + } + /* allocate memory for the padded output */ + if (rc == 0) { + rc = TPM_Malloc(bin_out, padBytes); + } + if (rc == 0) { + memset(*bin_out, 0, padBytes - bin_in_length); /* leading 0 padding */ + memcpy((*bin_out) + padBytes - bin_in_length, /* start copy after padding */ + bin_in, bin_in_length); + } + return rc; +} + +/* TPM_bin2bn() wraps the gnump function in a TPM error handler + + Converts a char array to bignum + + bn must be freed by the caller. +*/ + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, const unsigned char *bin, unsigned int bytes) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + rc = TPM_BN_new(bn_in); + } + if (rc == 0) { + mpz_t *bn = (mpz_t *)*bn_in; + mpz_import(*bn, /* output */ + bytes, /* count */ + 1, /* order, MSB first */ + 1, /* size, char */ + 0, /* endian, native (unused) */ + 0, /* nail, don't discard */ + bin); /* input */ + } + return rc; +} + +/* + Hash Functions +*/ + +/* TPM_SHA1InitCmd() initializes a platform dependent TPM_SHA1Context structure. + + The structure must be freed using TPM_SHA1FinalCmd() +*/ + +TPM_RESULT TPM_SHA1InitCmd(void **context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1InitCmd:\n"); + if (rc == 0) { + /* create a new freebl SHA1 context */ + *context = SHA1_NewContext(); + if (*context == NULL) { + printf("TPM_SHA1InitCmd: Error allocating a new context\n"); + rc = TPM_SIZE; + } + } + /* reset the SHA-1 context, preparing it for a fresh round of hashing */ + if (rc== 0) { + SHA1_Begin(*context); + } + return rc; +} + +/* TPM_SHA1UpdateCmd() adds 'data' of 'length' to the SHA-1 context + */ + +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1Update: length %u\n", length); + if (context != NULL) { + SHA1_Update(context, data, length); + } + else { + printf("TPM_SHA1Update: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1FinalCmd() extracts the SHA-1 digest 'md' from the context + */ + +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context) +{ + TPM_RESULT rc = 0; + unsigned int digestLen; + + printf(" TPM_SHA1FinalCmd:\n"); + if (rc== 0) { + if (context == NULL) { + printf("TPM_SHA1FinalCmd: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if (rc== 0) { + SHA1_End(context, md, &digestLen, TPM_DIGEST_SIZE); + /* Sanity check. For SHA1 it should always be 20 bytes. */ + if (digestLen != TPM_DIGEST_SIZE) { + printf("TPM_SHA1Final: Error (fatal), SHA1_End returned %u bytes\n", digestLen); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_SHA1Delete() zeros and frees the SHA1 context */ + +void TPM_SHA1Delete(void **context) +{ + if (*context != NULL) { + printf(" TPM_SHA1Delete:\n"); + /* zero because the SHA1 context might have data left from an HMAC */ + SHA1_DestroyContext(*context, PR_TRUE); + *context = NULL; + } + return; +} + +#if defined (__x86_64__) || \ + defined(__amd64__) || \ + defined(__ia64__) || \ + defined(__powerpc64__) || \ + defined(__s390x__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__aarch64__) + +#define IS_64 +typedef PRUint64 SHA_HW_t; + +#elif defined (__i386__) || \ + defined (__powerpc__) || \ + defined (__s390__) || \ + defined(__sparc__) || \ + defined(__arm__) + +typedef PRUint32 SHA_HW_t; +#undef IS_64 + +#else +#error "Cannot determine 32 or 64 bit platform" +#endif + +/* The structure returned by the SHA1_Flatten() command and passed to SHA1_Resurrect() + */ + +typedef struct SHA1SaveContextStrtd { + union { + PRUint32 w[16]; /* input buffer */ + PRUint8 b[64]; + } u; + PRUint64 size; /* count of hashed bytes. */ + SHA_HW_t H[22]; /* 5 state variables, 16 tmp values, 1 + extra */ +} SHA1SaveContextStr; + + +/* TPM_Sha1Context_Load() is non-portable code to deserialize the FreeBL SHA1 context. + + If the contextPresent prepended by TPM_Sha1Context_Store() is FALSE, context remains NULL. If + TRUE, context is allocated and loaded. +*/ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_BOOL contextPresent; /* is there a context to be loaded */ + uint32_t flattenSize; /* from the freebl library */ + SHA1Context *tmpContext = NULL; /* temp to get flatten size, freed @1 */ + uint32_t tmp32; /* temp to recreate 64-bit size */ + SHA1SaveContextStr restoreContext; + size_t i; + + printf(" TPM_Sha1Context_Load: FreeBL\n"); + /* TPM_Sha1Context_Store() stored a flag to indicate whether a context was stored */ + if (rc== 0) { + rc = TPM_LoadBool(&contextPresent, stream, stream_size); + printf(" TPM_Sha1Context_Load: contextPresent %u\n", contextPresent); + } + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_CheckTag(TPM_TAG_SHA1CONTEXT_FREEBL_V1, stream, stream_size); + } + /* check that context is NULL to detect memory leak */ + if ((rc== 0) && contextPresent) { + if (*context != NULL) { + printf("TPM_Sha1Context_Load: Error (fatal), *context %p should be NULL\n", *context ); + rc = TPM_FAIL; + } + } + /* create a temporary context just to get the freebl library size */ + if ((rc== 0) && contextPresent) { + rc = TPM_SHA1InitCmd((void **)&tmpContext); /* freed @1 */ + } + /* get the size of the FreeBL library SHA1 context */ + if ((rc== 0) && contextPresent) { + flattenSize = SHA1_FlattenSize(tmpContext); + /* sanity check that the freebl library and TPM structure here are in sync */ + if (flattenSize != sizeof(SHA1SaveContextStr)) { + printf("TPM_Sha1Context_Load: Error, " + "SHA1 context size %u from SHA1_FlattenSize not equal %lu from structure\n", + flattenSize, (unsigned long)sizeof(SHA1SaveContextStr)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* + deserialization code to fill in restoreContext + */ + /* b[0..63] <- u.b[0..63] (bytes only, no bytswapping) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Loadn(restoreContext.u.b, 64, stream, stream_size); + } + /* count <- size (this is 64 bits on all platforms) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.size = (uint64_t)tmp32 << 32; /* big endian */ + } + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.size += (uint64_t)tmp32 & 0xffffffff; /* big endian */ + } + for (i = 0 ; (rc == 0) && contextPresent && (i < 5) ; i++) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.H[i] = tmp32; /* H can be 32 or 64 bits */ + } + /* load the context */ + if ((rc== 0) && contextPresent) { + /* the size test above ensures that the cast here is safe */ + *context = SHA1_Resurrect((unsigned char *)&restoreContext, NULL); + if (*context == NULL) { + printf("TPM_Sha1Context_Load: Error, could not SHA1_Resurrect\n"); + rc = TPM_SIZE; + } + } + TPM_SHA1Delete((void *)&tmpContext); /* @1 */ + return rc; +} + +/* TPM_Sha1Context_Store() is non-portable code to serialize the FreeBL SHA1 context. context is + not altered. + + It prepends a contextPresent flag to the stream, FALSE if context is NULL, TRUE if not. +*/ + +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + size_t i; + unsigned int flattenSize; + SHA1SaveContextStr saveContext; + TPM_BOOL contextPresent; /* is there a context to be stored */ + + printf(" TPM_Sha1Context_Store: FreeBL\n"); + /* store contextPresent */ + if (rc == 0) { + if (context != NULL) { + printf(" TPM_Sha1Context_Store: Storing context\n"); + contextPresent = TRUE; + } + else { + printf(" TPM_Sha1Context_Store: No context to store\n"); + contextPresent = FALSE; + } + printf(" TPM_Sha1Context_Store: contextPresent %u \n", contextPresent); + rc = TPM_Sbuffer_Append(sbuffer, &contextPresent, sizeof(TPM_BOOL)); + } + /* overall format tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SHA1CONTEXT_FREEBL_V1); + } + if ((rc== 0) && contextPresent) { + /* get the size of the FreeBL SHA1 context */ + flattenSize = SHA1_FlattenSize(context); /* it will not be NULL here */ + /* sanity check that the freebl library and TPM structure here are in sync */ + if (flattenSize != sizeof(SHA1SaveContextStr)) { + printf("TPM_Sha1Context_Store: Error (fatal), " + "SHA1 context size %u from SHA1_FlattenSize not equal %lu from structure\n", + flattenSize, (unsigned long)sizeof(SHA1SaveContextStr)); + rc = TPM_FAIL; + } + } + /* store into the structure from the library */ + if ((rc== 0) && contextPresent) { + /* the size test above ensures that the cast here is safe */ + rv = SHA1_Flatten(context, (unsigned char *)&saveContext); + if (rv != SECSuccess) { + printf("TPM_Sha1Context_Store: Error (fatal), SHA1_Flatten rv %d\n", rv); + rc = TPM_FAIL; + } + } + /* + append the FreeBL SHA1 context to the stream + */ + /* b[0..63] <- u.b[0..63] (bytes only, no byte swapping) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append(sbuffer, saveContext.u.b, 64); + } + /* count <- size (this is 64 bits on all platforms) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.size >> 32); /* big endian */ + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.size & 0xffffffff); + } + /* SHA_HW_t - NSS uses 64 bits on 64 bit platforms for performance reasons only. The lower 32 + bits are critical, so you can always serialize/deserialize just the lower 32 bits. */ + /* The remainder of the H array is scratch memory and does not need to be preserved or + transmitted. */ + for (i = 0 ; (rc == 0) && contextPresent && (i < 5) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.H[i] & 0xffffffff); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +#ifdef TPM_AES + +/* TPM_SymmetricKeyData_New() allocates memory for and initializes a TPM_SYMMETRIC_KEY_DATA token. + */ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_New:\n"); + if (rc == 0) { + rc = TPM_Malloc(tpm_symmetric_key_data, sizeof(TPM_SYMMETRIC_KEY_DATA)); + } + if (rc == 0) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Free() initializes the key token to wipe secrets. It then frees the + TPM_SYMMETRIC_KEY_DATA token and sets it to NULL. +*/ + +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + printf(" TPM_SymmetricKeyData_Free:\n"); + if (*tpm_symmetric_key_data != NULL) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + free(*tpm_symmetric_key_data); + *tpm_symmetric_key_data = NULL; + } + return; +} + +/* TPM_SymmetricKeyData_Init() is AES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + /* zero to wipe secrets */ + memset(tpm_symmetric_key_data->userKey, 0, sizeof(tpm_symmetric_key_data->userKey)); + return; +} + +/* TPM_SymmetricKeyData_Load() is AES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* The AES key is a simple array. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey), + stream, stream_size); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() is AES non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store AES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_symmetric_key_data->userKey, + sizeof(tpm_symmetric_key_data->userKey)); + } + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is AES non-portable code to generate a random symmetric key + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + rc = TPM_Random(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey)); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is AES non-portable code to CBC encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx; + uint32_t pad_length; + uint32_t output_length; /* dummy */ + unsigned char *decrypt_data_pad; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + cx = NULL; /* freed @2 */ + + /* sanity check that the AES key has previously been generated */ + if (rc == 0) { + if (!tpm_symmetric_key_data->valid) { + printf("TPM_SymmetricKeyData_Encrypt: Error (fatal), AES key not valid\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + /* calculate the PKCS#7 / RFC2630 pad length and padded data length */ + pad_length = TPM_AES_BLOCK_SIZE - (decrypt_length % TPM_AES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* create a new AES context */ + cx = AES_CreateContext(tpm_symmetric_key_data->userKey, + ivec, /* CBC initialization vector */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_Encrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* encrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Input", decrypt_data_pad); + /* perform the AES encryption */ + rv = AES_Encrypt(cx, + *encrypt_data, &output_length, *encrypt_length, /* output */ + decrypt_data_pad, *encrypt_length); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_Encrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Output", *encrypt_data); + } + free(decrypt_data_pad); /* @1 */ + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + unsigned char dummy_ivec[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + memset(dummy_ivec, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + dummy_ivec, /* ivec */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is AES non-portable code to CBC decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx; + uint32_t pad_length; + uint32_t output_length; /* dummy */ + uint32_t i; + unsigned char *pad_data; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + cx = NULL; /* freed @1 */ + + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_AES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* sanity check that the AES key has previously been generated */ + if (rc == 0) { + if (!tpm_symmetric_key_data->valid) { + printf("TPM_SymmetricKeyData_Decrypt: Error (fatal), AES key not valid\n"); + rc = TPM_FAIL; + } + } + /* allocate memory for the PKCS#7 / RFC2630 padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* create a new AES context */ + cx = AES_CreateContext(tpm_symmetric_key_data->userKey, + ivec, /* CBC initialization vector */ + NSS_AES_CBC, /* CBC mode */ + FALSE, /* decrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_Decrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + /* decrypt the input to the PKCS#7 / RFC2630 padded output */ + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Input", encrypt_data); + /* perform the AES decryption */ + rv = AES_Decrypt(cx, + *decrypt_data, &output_length, encrypt_length, /* output */ + encrypt_data, encrypt_length); /* input */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_Decrypt: Error, rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Output", *decrypt_data); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_AES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + unsigned char dummy_ivec[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + memset(dummy_ivec, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + dummy_ivec, /* ivec */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @1 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_CtrCrypt() does an encrypt or decrypt (they are the same XOR operation with + a CTR mode pad) of 'data_in' to 'data_out'. + + TPM_SymmetricKeyData_CtrCrypt() is a TPM variant of the standard CTR encrypt function that + increments only the low 4 bytes of the counter. + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ctr_in' is the initial CTR value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + const unsigned char *ctr_in, /* input */ + uint32_t ctr_in_size) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx = NULL; + unsigned char ctr[TPM_AES_BLOCK_SIZE]; + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + uint32_t output_length; /* dummy */ + uint32_t cint; /* counter as a 32-bit integer */ + + printf(" TPM_SymmetricKeyData_CtrCrypt: data_size %u\n", data_size); + symmetric_key_size = symmetric_key_size; + /* check the input CTR size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ctr_in_size < sizeof(ctr)) { + printf(" TPM_SymmetricKeyData_CtrCrypt: Error (fatal)" + ", CTR size %u too small for AES key\n", ctr_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of CTR, since this function alters the value */ + memcpy(ctr, ctr_in, sizeof(ctr)); + TPM_PrintFour(" TPM_SymmetricKeyData_CtrCrypt: CTR", ctr); + } + /* create a new AES context */ + if (rc == 0) { + cx = AES_CreateContext(symmetric_key, /* AES key */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + while (data_size != 0) { + printf(" TPM_SymmetricKeyData_CtrCrypt : data_size remaining %u\n", data_size); + /* initialize the context each time through the loop */ + if (rc == 0) { + rv = AES_InitContext(cx, /* AES context */ + symmetric_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + /* get an XOR pad array by encrypting the CTR with the AES key */ + if (rc == 0) { + rv = AES_Encrypt(cx, + pad_buffer, &output_length, TPM_AES_BLOCK_SIZE, /* output */ + ctr, TPM_AES_BLOCK_SIZE); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, increment CTR, only the low 4 bytes */ + if (data_size != 0) { + /* CTR is a big endian array, so the low 4 bytes are used */ + cint = LOAD32(ctr, TPM_AES_BLOCK_SIZE-4); /* byte array to uint32_t */ + cint++; /* increment */ + STORE32(ctr, TPM_AES_BLOCK_SIZE-4, cint); /* uint32_t to byte array */ + } + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_OfbCrypt() does an encrypt or decrypt (they are the same XOR operation with + a OFB mode pad) of 'data_in' to 'data_out' + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ivec_in' is the initial IV value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* in */ + uint32_t symmetric_key_size, /* in */ + unsigned char *ivec_in, /* input */ + uint32_t ivec_in_size) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx = NULL; + unsigned char ivec_loop[TPM_AES_BLOCK_SIZE]; /* ivec input to loop */ + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + uint32_t output_length; /* dummy */ + + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size %u\n", data_size); + symmetric_key_size = symmetric_key_size; + /* check the input OFB size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ivec_in_size < TPM_AES_BLOCK_SIZE) { + printf(" TPM_SymmetricKeyData_OfbCrypt: Error (fatal)," + "IV size %u too small for AES key\n", ivec_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + /* first time through, the ivec_loop will be the input ivec */ + if (rc == 0) { + memcpy(ivec_loop, ivec_in, sizeof(ivec_loop)); + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec_loop); + } + /* create a new AES context */ + if (rc == 0) { + cx = AES_CreateContext(symmetric_key, + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + while (data_size != 0) { + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size remaining %u\n", data_size); + /* initialize the context each time through the loop */ + if (rc == 0) { + rv = AES_InitContext(cx, /* AES context */ + symmetric_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + /* get an XOR pad array by encrypting the IV with the AES key */ + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec_loop); + rv = AES_Encrypt(cx, + pad_buffer, &output_length, TPM_AES_BLOCK_SIZE, /* output */ + ivec_loop, TPM_AES_BLOCK_SIZE); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, wrap the pad_buffer back to ivec_loop (output feed back) */ + memcpy(ivec_loop, pad_buffer, TPM_AES_BLOCK_SIZE); + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +#endif /* TPM_AES */ diff --git a/src/tpm12/tpm_cryptoh.c b/src/tpm12/tpm_cryptoh.c new file mode 100644 index 0000000..36df6aa --- /dev/null +++ b/src/tpm12/tpm_cryptoh.c @@ -0,0 +1,5427 @@ +/********************************************************************************/ +/* */ +/* High Level Platform Independent Cryptography */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_cryptoh.c 4540 2011-04-07 18:51:34Z 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 <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "tpm_admin.h" +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_migration.h" +#include "tpm_nonce.h" +#include "tpm_key.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_store.h" +#include "tpm_ver.h" + +#include "tpm_cryptoh.h" + +/* local prototypes */ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap); +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC hmac, + const TPM_SECRET key, + va_list ap); + +static TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, + void **sha1_context, + TPM_SIZED_BUFFER *hashData); + +/* + TPM_SIGN_INFO +*/ + +/* TPM_SignInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Init:\n"); + memset(tpm_sign_info->fixed, 0, TPM_SIGN_INFO_FIXED_SIZE); + TPM_Nonce_Init(tpm_sign_info->replay); + TPM_SizedBuffer_Init(&(tpm_sign_info->data)); + return; +} + +/* TPM_SignInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIGN_INFO *tpm_sign_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SignInfo_Store:\n"); + /* store the tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SIGNINFO); + } + /* store the fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_sign_info->fixed, TPM_SIGN_INFO_FIXED_SIZE); + } + /* store the replay */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_sign_info->replay); + } + /* store the dataLen and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sign_info->data)); + } + if (rc == 0) { + const unsigned char *buffer; + uint32_t length; + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_SignInfo_Store: Buffer", buffer, length); + } + return rc; +} + +/* TPM_SignInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the sign_info + sets pointers to NULL + calls TPM_SignInfo_Init to set members back to default values + The sign_info itself is not freed +*/ + +void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Delete:\n"); + if (tpm_sign_info != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sign_info->data)); + TPM_SignInfo_Init(tpm_sign_info); + } + return; +} + +/* + TPM_CERTIFY_INFO +*/ + +/* TPM_CertifyInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Init:\n"); + TPM_StructVer_Init(&(tpm_certify_info->version)); + tpm_certify_info->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info->keyFlags = 0; + tpm_certify_info->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info->algorithmParms)); + TPM_Digest_Init(tpm_certify_info->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info->data); + tpm_certify_info->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info->pcrInfo)); + tpm_certify_info->tpm_pcr_info = NULL; + return; +} + +#if 0 +/* TPM_CertifyInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo_Init() + After use, call TPM_CertifyInfo_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Load:\n"); + /* load version */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_certify_info->version), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_certify_info->version)); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_certify_info->tpm_pcr_info), + &(tpm_certify_info->pcrInfo)); + } + return rc; +} +#endif + +/* TPM_CertifyInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO *tpm_certify_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Store:\n"); + /* store version */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_certify_info->version)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info->pcrInfo), + tpm_certify_info->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info->pcrInfo)); + } + return rc; +} + +/* TPM_CertifyInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Delete:\n"); + if (tpm_certify_info != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info->pcrInfo)); + /* pcr cache */ + TPM_PCRInfo_Delete(tpm_certify_info->tpm_pcr_info); + free(tpm_certify_info->tpm_pcr_info); + TPM_CertifyInfo_Init(tpm_certify_info); + } + return; +} + +/* TPM_CertifyInfo_Set() fills in tpm_certify_info with the information from the key pointed to be + tpm_key +*/ + +TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Set:\n"); + if (rc == 0) { + tpm_certify_info->keyUsage = tpm_key->keyUsage; + tpm_certify_info->keyFlags = tpm_key->keyFlags; + tpm_certify_info->authDataUsage = tpm_key->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_certify_info->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_CERTIFY_INFO2 +*/ + +/* TPM_CertifyInfo2_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Init:\n"); + tpm_certify_info2->fill = 0x00; + tpm_certify_info2->payloadType = TPM_PT_ASYM; + tpm_certify_info2->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info2->keyFlags = 0; + tpm_certify_info2->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info2->algorithmParms)); + TPM_Digest_Init(tpm_certify_info2->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info2->data); + tpm_certify_info2->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info2->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_certify_info2->migrationAuthority)); + tpm_certify_info2->tpm_pcr_info_short = NULL; + return; +} + +#if 0 +/* TPM_CertifyInfo2_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo2_Init() + After use, call TPM_CertifyInfo2_Delete() to free memory +*/ + +TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CERTIFY_INFO2, stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->fill), stream, stream_size); + } + /* check fill immediately to ease debugging */ + if (rc == 0) { + if (tpm_certify_info2->fill != 0x00) { + printf("TPM_CertifyInfo2_Load: Error checking fill %02x\n", tpm_certify_info2->fill); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load payloadType */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->payloadType), stream, stream_size); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info2->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info2->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info2->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info2->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info2->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info2->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO2 tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_CreateFromBuffer(&(tpm_certify_info2->tpm_pcr_info_short), + &(tpm_certify_info2->pcrInfo)); + } + /* load migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->migrationAuthority), stream, stream_size); + } + /* check migrationAuthority immediately to ease debugging */ + if (rc == 0) { + if ((tpm_certify_info2->migrationAuthority.buffer != NULL) && + (tpm_certify_info2->migrationAuthority.size != TPM_DIGEST_SIZE)) { + printf("TPM_CertifyInfo2_Load: Error checking migrationAuthority %p, %u\n", + tpm_certify_info2->migrationAuthority.buffer, + tpm_certify_info2->migrationAuthority.size); + rc = TPM_INVALID_STRUCTURE; + } + } + return rc; +} +#endif + +/* TPM_CertifyInfo2_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CERTIFY_INFO2); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->fill), sizeof(BYTE)); + } + /* store payloadType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->payloadType), + sizeof(TPM_PAYLOAD_TYPE)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info2->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info2->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info2->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info2->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info2->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info2->pcrInfo), + tpm_certify_info2->tpm_pcr_info_short, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoShort_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->pcrInfo)); + } + /* store migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->migrationAuthority)); + } + return rc; +} + +/* TPM_CertifyInfo2_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo2_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Delete:\n"); + if (tpm_certify_info2 != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info2->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info2->pcrInfo)); + /* pcr cache */ + TPM_PCRInfoShort_Delete(tpm_certify_info2->tpm_pcr_info_short); + free(tpm_certify_info2->tpm_pcr_info_short); + TPM_SizedBuffer_Delete(&(tpm_certify_info2->migrationAuthority)); + TPM_CertifyInfo2_Init(tpm_certify_info2); + } + return; +} + +/* TPM_CertifyInfo2_Set() fills in tpm_certify_info2 with the information from the key pointed to by + tpm_key. + +*/ + +TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_CertifyInfo_Set:\n"); + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + tpm_certify_info2->payloadType = tpm_store_asymkey->payload; + tpm_certify_info2->keyUsage = tpm_key->keyUsage; + tpm_certify_info2->keyFlags = tpm_key->keyFlags; + tpm_certify_info2->authDataUsage = tpm_key->authDataUsage; + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(tpm_certify_info2->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info2->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY +*/ + +/* TPM_SymmetricKey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Init:\n"); + tpm_symmetric_key->algId = 0; + tpm_symmetric_key->encScheme = TPM_ES_NONE; + tpm_symmetric_key->size = 0; + tpm_symmetric_key->data = NULL; + return; +} + +/* TPM_SymmetricKey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SymmetricKey_Init() + After use, call TPM_SymmetricKey_Delete() to free memory +*/ + +TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Load:\n"); + /* load algId */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_symmetric_key->algId), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->encScheme), stream, stream_size); + } + /* load size */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->size), stream, stream_size); + } + /* allocate memory for the data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Malloc(&(tpm_symmetric_key->data), tpm_symmetric_key->size); + } + /* load data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Loadn(tpm_symmetric_key->data, tpm_symmetric_key->size, stream, stream_size); + } + return rc; +} + +/* TPM_SymmetricKey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Store:\n"); + /* store algId */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_symmetric_key->algId); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->encScheme); + } + /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ + /* store size */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->size); + } + /* store data */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key->data, tpm_symmetric_key->size); + } + return rc; +} + +/* TPM_SymmetricKey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SymmetricKey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Delete:\n"); + if (tpm_symmetric_key != NULL) { + free(tpm_symmetric_key->data); + TPM_SymmetricKey_Init(tpm_symmetric_key); + } + return; +} + +/* TPM_SymmetricKeyData_EncryptSbuffer() encrypts 'sbuffer' to 'encrypt_data' + + Padding is included, so the output may be larger than the input. + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, + TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_SymmetricKeyData_EncryptSbuffer:\n"); + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* platform dependent symmetric key encrypt */ + rc = TPM_SymmetricKeyData_Encrypt(&(encrypt_data->buffer), /* output, caller frees */ + &(encrypt_data->size), /* output */ + decrypt_data, /* input */ + decrypt_data_size, /* input */ + tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_StreamCrypt() encrypts or decrypts 'data_in' to 'data_out ' + + It assumes that the size of data_out and data_in are equal, and that a stream cipher mode is + used. For the supported stream ciphers, encrypt and decrypt are equivalent, so no direction flag + is required. + + AES 128 with CTR or OFB modes are supported. For CTR mode, pad is the initial count. For OFB + mode, pad is the IV. +*/ + +TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + TPM_ALGORITHM_ID algId, /* algorithm */ + TPM_ENC_SCHEME encScheme, /* mode */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + unsigned char *pad_in, /* input */ + uint32_t pad_in_size) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_StreamCrypt:\n"); + switch (algId) { + case TPM_ALG_AES128: + switch (encScheme) { + case TPM_ES_SYM_CTR: + rc = TPM_SymmetricKeyData_CtrCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + case TPM_ES_SYM_OFB: + rc = TPM_SymmetricKeyData_OfbCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad AES128 encScheme %04x\n", + encScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad algID %08x\n", algId); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + return rc; +} + +/* These functions perform high-level, platform independent functions. + They call the lower level, platform dependent crypto functions in + tpm_crypto.c +*/ + +/* TPM_SHA1Sbuffer() calculates the SHA-1 digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating a digest on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_SHA1Sbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintFour(" TPM_SHA1Sbuffer: input", buffer); + /* hash the serialized buffer to tpm_digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_SHA1_GenerateStructure() generates a SHA-1 digest of a structure. It serializes the + structure and hashes the result. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_SHA1_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SHA1_CheckStructure() generates a SHA-1 digest of a structure. It serializes the structure + and hashes the result. It compares the result to 'expected_digest' and returns 'error' on + mismatch. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + + + +TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_DIGEST actual_digest; + + printf(" TPM_SHA1_CheckStructure:\n"); + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(actual_digest, tpmStructure, storeFunction); + } + /* check the digests */ + if (rc == 0) { + rc = TPM_Digest_Compare(actual_digest, expected_digest); + if (rc != 0) { + rc = error; + } + } + return rc; +} + +/* TPM_SHA1() can be called directly to hash a list of streams. + + The ... arguments to be hashed are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + */ + +TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_SHA1:\n"); + va_start(ap, md); + rc = TPM_SHA1_valist(md, 0, NULL, ap); + va_end(ap); + return rc; +} + +/* TPM_SHA1_Check() digests the list of streams and compares the result to 'digest_expect' + */ + +TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...) +{ + TPM_RESULT rc = 0; + TPM_DIGEST digest_actual; + va_list ap; + + printf(" TPM_SHA1_Check:\n"); + if (rc == 0) { + va_start(ap, digest_expect); + rc = TPM_SHA1_valist(digest_actual, 0, NULL, ap); + va_end(ap); + } + if (rc == 0) { + rc = TPM_Digest_Compare(digest_expect, digest_actual); + } + return rc; +} + +/* TPM_SHA1_valist() is the internal function, called with the va_list already created. + + It is called from TPM_SHA1() to do a simple hash. Typically length0==0 and buffer0==NULL. + + It can also be called from the HMAC function to hash the variable number of input parameters. In + that case, the va_list for the text is already formed. length0 and buffer0 are used to input the + padded key. +*/ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap) +{ + TPM_RESULT rc = 0; + uint32_t length; + unsigned char *buffer; + void *context = NULL; /* platform dependent context */ + TPM_BOOL done = FALSE; + + printf(" TPM_SHA1_valist:\n"); + if (rc == 0) { + rc = TPM_SHA1InitCmd(&context); + } + if (rc == 0) { + if (length0 !=0) { /* optional first text block */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length0); + rc = TPM_SHA1UpdateCmd(context, buffer0, length0); /* hash the buffer */ + } + } + while ((rc == 0) && !done) { + length = va_arg(ap, uint32_t); /* first vararg is the length */ + if (length != 0) { /* loop until a zero length argument terminates */ + buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length); + rc = TPM_SHA1UpdateCmd(context, buffer, length); /* hash the buffer */ + } + else { + done = TRUE; + } + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(md, context); + } + if (rc == 0) { + TPM_PrintFour(" TPM_SHA1_valist: Digest", md); + } + /* call TPM_SHA1Delete even if there was an error */ + TPM_SHA1Delete(&context); + return rc; +} + +/* TPM_HMAC_GenerateSbuffer() calculates the HMAC digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating an HMAC on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_GenerateSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Generate(tpm_hmac, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_GenerateStructure() generates an HMAC of a structure. It serializes the structure and + HMAC's the result. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_HMAC_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_HMAC_GenerateSbuffer(tpm_hmac, hmac_key, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_HMAC_Generate() can be called directly to HMAC a list of streams. + + The ... arguments are a message list of the form + size_t length, unsigned char *buffer + terminated by a 0 length +*/ + +TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_HMAC_Generate:\n"); + va_start(ap, hmac_key); + rc = TPM_HMAC_Generatevalist(tpm_hmac, hmac_key, ap); + va_end(ap); + return rc; +} + +/* TPM_HMAC_Generatevalist() is the internal function, called with the va_list already created. + + It is called from TPM_HMAC_Generate() and TPM_HMAC_Check() with the va_list for the text already + formed. +*/ + +#define TPM_HMAC_BLOCK_SIZE 64 + +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC tpm_hmac, + const TPM_SECRET key, + va_list ap) +{ + TPM_RESULT rc = 0; + unsigned char ipad[TPM_HMAC_BLOCK_SIZE]; + unsigned char opad[TPM_HMAC_BLOCK_SIZE]; + size_t i; + TPM_DIGEST inner_hash; + + printf(" TPM_HMAC_Generatevalist:\n"); + /* calculate key XOR ipad and key XOR opad */ + if (rc == 0) { + /* first part, key XOR pad */ + for (i = 0 ; i < TPM_AUTHDATA_SIZE ; i++) { + ipad[i] = key[i] ^ 0x36; /* magic numbers from RFC 2104 */ + opad[i] = key[i] ^ 0x5c; + } + /* second part, 0x00 XOR pad */ + memset(ipad + TPM_AUTHDATA_SIZE, 0x36, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + memset(opad + TPM_AUTHDATA_SIZE, 0x5c, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + /* calculate the inner hash, hash the key XOR ipad and the text */ + rc = TPM_SHA1_valist(inner_hash, + TPM_HMAC_BLOCK_SIZE, ipad, ap); + } + /* hash the key XOR opad and the previous hash */ + if (rc == 0) { + rc = TPM_SHA1(tpm_hmac, + TPM_HMAC_BLOCK_SIZE, opad, + TPM_DIGEST_SIZE, inner_hash, + 0, NULL); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Generatevalist: HMAC", tpm_hmac); + } + return rc; +} + +/* TPM_HMAC_CheckSbuffer() checks the HMAC of a TPM_STORE_BUFFER. + + This is commonly used when checking an HMAC on a serialized structure. Structures are serialized + to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, /* result */ + TPM_HMAC expect, /* expected */ + const TPM_SECRET hmac_key, /* key */ + TPM_STORE_BUFFER *sbuffer) /* data stream */ +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_CheckSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Check(valid, + expect, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_Check() can be called directly to check the HMAC of a list of streams. + + The ... arguments are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + +*/ + +TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + TPM_HMAC actual; + int result; + + printf(" TPM_HMAC_Check:\n"); + va_start(ap, key); + if (rc == 0) { + rc = TPM_HMAC_Generatevalist(actual, key, ap); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Check: Calculated", actual); + TPM_PrintFour(" TPM_HMAC_Check: Received ", expect); + result = memcmp(expect, actual, TPM_DIGEST_SIZE); + if (result == 0) { + *valid = TRUE; + } + else { + *valid = FALSE; + } + } + va_end(ap); + return rc; +} + +/* TPM_HMAC_CheckStructure() is a generic function that checks the integrity HMAC of a structure. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + expect is the expected HMAC, a member of the structure + storeFunction is the serialization function for the structure + error is the failure return code + + The function saves a copy of the expected HMAC, and then NULL's the structure member. It + serializes the structure, generates an HMAC, and compares it to the expected value. + + As a side effect, the structure member is zeroed. +*/ + +TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_HMAC expect, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + TPM_HMAC saveExpect; + TPM_BOOL valid; + + printf(" TPM_HMAC_CheckStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + TPM_Digest_Copy(saveExpect, expect); /* save the expected value */ + TPM_Digest_Init(expect); /* set value in structure to NULL */ + rc = storeFunction(&sbuffer, + tpmStructure); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(&valid, /* result */ + saveExpect, /* expected */ + hmac_key, /* key */ + &sbuffer); /* data stream */ + } + if (rc == 0) { + if (!valid) { + printf("TPM_HMAC_CheckStructure: Error checking HMAC\n"); + rc = error; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_XOR XOR's 'in1' and 'in2' of 'length', putting the result in 'out' + +*/ + +void TPM_XOR(unsigned char *out, + const unsigned char *in1, + const unsigned char *in2, + size_t length) +{ + size_t i; + + for (i = 0 ; i < length ; i++) { + out[i] = in1[i] ^ in2[i]; + } + return; +} + +/* TPM_MGF1() generates an MGF1 'array' of length 'arrayLen' from 'seed' of length 'seedlen' + + The openSSL DLL doesn't export MGF1 in Windows or Linux 1.0.0, so this version is created from + scratch. + + Algorithm and comments (not the code) from: + + PKCS #1: RSA Cryptography Specifications Version 2.1 B.2.1 MGF1 + + Prototype designed to be compatible with openSSL + + MGF1 is a Mask Generation Function based on a hash function. + + MGF1 (mgfSeed, maskLen) + + Options: + + Hash hash function (hLen denotes the length in octets of the hash + function output) + + Input: + + mgfSeed seed from which mask is generated, an octet string + maskLen intended length in octets of the mask, at most 2^32(hLen) + + Output: + mask mask, an octet string of length l; or "mask too long" + + Error: "mask too long' +*/ + +TPM_RESULT TPM_MGF1(unsigned char *mask, + uint32_t maskLen, + const unsigned char *mgfSeed, + uint32_t mgfSeedlen) +{ + TPM_RESULT rc = 0; + unsigned char counter[4]; /* 4 octets */ + uint32_t count; /* counter as an integral type */ + uint32_t outLen; + TPM_DIGEST lastDigest; + + printf(" TPM_MGF1: Output length %u\n", maskLen); + if (rc == 0) { + /* this is possible with arrayLen on a 64 bit architecture, comment to quiet beam */ + if ((maskLen / TPM_DIGEST_SIZE) > 0xffffffff) { /*constant condition*/ + printf(" TPM_MGF1: Error (fatal), Output length too large for 32 bit counter\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* 1.If l > 2^32(hLen), output "mask too long" and stop. */ + /* NOTE Checked by caller */ + /* 2. Let T be the empty octet string. */ + /* 3. For counter from 0 to [masklen/hLen] - 1, do the following: */ + for (count = 0, outLen = 0 ; (rc == 0) && (outLen < maskLen) ; count++) { + /* a. Convert counter to an octet string C of length 4 octets - see Section 4.1 */ + /* C = I2OSP(counter, 4) NOTE Basically big endian */ + uint32_t count_n = htonl(count); + memcpy(counter, &count_n, 4); + /* b.Concatenate the hash of the seed mgfSeed and C to the octet string T: */ + /* T = T || Hash (mgfSeed || C) */ + /* If the entire digest is needed for the mask */ + if ((outLen + TPM_DIGEST_SIZE) < maskLen) { + rc = TPM_SHA1(mask + outLen, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + outLen += TPM_DIGEST_SIZE; + } + /* if the mask is not modulo TPM_DIGEST_SIZE, only part of the final digest is needed */ + else { + /* hash to a temporary digest variable */ + rc = TPM_SHA1(lastDigest, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + /* copy what's needed */ + memcpy(mask + outLen, lastDigest, maskLen - outLen); + outLen = maskLen; /* outLen = outLen + maskLen - outLen */ + } + } + /* 4.Output the leading l octets of T as the octet string mask. */ + return rc; +} + +/* TPM_MGF1_GenerateArray() generates an array of length arrayLen using the varargs as the seed. + + Since the seed is a known length, it is passed in rather that extracted from the varargs. If the + seed length turns out to be wrong once the varargs are parsed, TPM_FAIL is returned. + + 'array' must be freed by the caller. +*/ + +TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, + uint32_t arrayLen, + uint32_t seedLen, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + unsigned char *seed; /* constructed MGF1 seed */ + size_t vaLength; /* next seed segment length */ + unsigned char *vaBuffer; /* next seed segment buffer */ + uint32_t seedLeft; /* remaining seed bytes required */ + unsigned char *seedBuffer; /* running pointer to the seed array */ + TPM_BOOL done = FALSE; /* done when a vaLength == 0 is reached */ + + printf(" TPM_MGF1_GenerateArray: arrayLen %u seedLen %u\n", arrayLen, seedLen); + seed = NULL; /* freed @1 */ + *array = NULL; /* freed by caller */ + va_start(ap, seedLen); + /* allocate temporary memory for the seed */ + if (rc == 0) { + rc = TPM_Malloc(&seed, seedLen); + seedBuffer = seed; + seedLeft = seedLen; + } + /* construct the seed */ + while ((rc == 0) && !done) { + vaLength = (size_t)va_arg(ap, uint32_t); /* first vararg is the length */ + if (vaLength != 0) { /* loop until a zero length argument terminates */ + if (rc == 0) { + printf(" TPM_MGF1_GenerateArray: Appending %lu bytes\n", (unsigned long)vaLength); + if (vaLength > seedLeft) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too small\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + vaBuffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + memcpy(seedBuffer, vaBuffer, vaLength); + seedBuffer += vaLength; + seedLeft-= vaLength; + } + } + else { + done = TRUE; + if (seedLeft != 0) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too large by %u\n", + seedLeft); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + } + /* allocate memory for the array */ + if (rc == 0) { + rc = TPM_Malloc(array, arrayLen); + } + /* generate the MGF1 array */ + if (rc == 0) { + TPM_MGF1(*array, + arrayLen, + seed, + seedLen); + TPM_PrintFour(" TPM_MGF1_GenerateArray: MGF1", *array); + } + va_end(ap); + free(seed); /* @1 */ + return rc; +} + +/* TPM_bn2binMalloc() allocates a buffer 'bin' and loads it from 'bn'. + 'bytes' is set to the allocated size of 'bin'. + + If padBytes is non-zero, 'bin' is padded with leading zeros if necessary, so that 'bytes' will + equal 'padBytes'. This is used when TPM data structures expect a fixed length while the crypto + library 'bn to bin' function might truncates leading zeros. + + '*bin' must be freed by the caller +*/ + +TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, /* freed by caller */ + unsigned int *bytes, + TPM_BIGNUM bn, + uint32_t padBytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_bn2binMalloc: padBytes %u\n", padBytes); + /* number of bytes required in the bin array */ + if (rc == 0) { + rc = TPM_BN_num_bytes(bytes, bn); + } + /* calculate the array size to malloc */ + if (rc == 0) { + /* padBytes 0 says that no padding is required */ + if (padBytes == 0) { + padBytes = *bytes; /* setting equal yields no padding */ + } + /* if the array with padding is still less than the number of bytes required by the bignum, + this function fails */ + if (padBytes < *bytes) { + printf("TPM_bn2binMalloc: Error, " + "padBytes %u less than BN bytes %u\n", padBytes, *bytes); + rc = TPM_SIZE; + } + /* log if padding is occurring */ + if (padBytes != *bytes) { + printf(" TPM_bn2binMalloc: padBytes %u bytes %u\n", padBytes, *bytes); + } + } + /* allocate for the padded array */ + if (rc == 0) { + rc = TPM_Malloc(bin, padBytes); + *bytes = padBytes; + } + /* call the bignum to bin conversion */ + if (rc == 0) { + rc = TPM_bn2binArray(*bin, padBytes, bn); + } + return rc; +} + +/* TPM_bn2binArray() loads the array 'bin' of size 'bytes' from 'bn' + + The data from 'bn' is right justified and zero padded. +*/ + +TPM_RESULT TPM_bn2binArray(unsigned char *bin, + unsigned int bytes, + TPM_BIGNUM bn) +{ + TPM_RESULT rc = 0; + unsigned int numBytes; + + printf(" TPM_bn2binArray: size %u\n", bytes); + if (rc == 0) { + /* zero pad */ + memset(bin, 0, bytes); + /* bytes required for the bignum */ + rc = TPM_BN_num_bytes(&numBytes, bn); + } + /* if the array is less than the number of bytes required by the bignum, this function fails */ + if (rc == 0) { + printf(" TPM_bn2binArray: numBytes in bignum %u\n", numBytes); + if (numBytes > bytes) { + printf("TPM_bn2binArray: Error, " + "BN bytes %u greater than array bytes %u\n", numBytes, bytes); + rc = TPM_SIZE; + } + } + if (rc == 0) { + /* if there are bytes in the bignum (it is not zero) */ + if (numBytes > 0) { + rc = TPM_bn2bin(bin + bytes - numBytes, /* store right justified */ + bn); + } + } + return rc; +} + +/* TPM_2bin2bn() converts two byte arrays to a positive BIGNUM. + + The two byte arrays are concatenated. The concatenation is used to create the BIGNUM. + + bignum must be freed by the caller. +*/ + +TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, /* freed by caller */ + const unsigned char *bin0, uint32_t size0, + const unsigned char *bin1, uint32_t size1) +{ + TPM_RESULT rc = 0; /* TPM return code */ + TPM_STORE_BUFFER sBuffer; /* used of >1 element or first element is negative */ + const unsigned char *buffer; + uint32_t size; + + printf(" TPM_bin2bn:\n"); + TPM_Sbuffer_Init(&sBuffer); /* freed @1 */ + /* append the first element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin0, size0); + } + /* append the next element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin1, size1); + } + /* create the BIGNUM from the array */ + if (rc == 0) { + TPM_Sbuffer_Get(&sBuffer, &buffer, &size); + /* create the BIGNUM */ + rc = TPM_bin2bn(bignum_in, buffer, size); /* freed by caller */ + } + TPM_Sbuffer_Delete(&sBuffer); /* @1 */ + return rc; +} + +/* TPM_RSAPrivateDecryptMalloc() allocates a buffer 'decrypt_data' of size 'decrypt_data_size' + and then calls TPM_RSAPrivateDecryptH(). +*/ + +TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* allocate space for the decrypted blob */ + printf(" TPM_RSAPrivateDecryptMalloc: Return max data size %u bytes\n", + tpm_key->pubKey.size); + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, tpm_key->pubKey.size); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecryptH(*decrypt_data, + decrypt_data_length, + tpm_key->pubKey.size, + encrypt_data, + encrypt_data_size, + tpm_key); + } + return rc; +} + +/* TPM_RSAPrivateDecryptH() decrypts 'encrypt_data' using the private key in + 'tpm_key' and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + uint32_t decrypt_data_size, /* size of decrypt_data buffer */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSAPrivateDecryptH: Data size %u bytes\n", encrypt_data_size); + TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Encrypt data", encrypt_data, encrypt_data_size); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPrivateDecryptH: Error, NULL key\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + /* check the key size vs the data size */ + if (rc == 0) { + if (encrypt_data_size > nbytes) { + printf("TPM_RSAPrivateDecryptH: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + if (rc == 0) { + /* debug printing */ + printf(" TPM_RSAPrivateDecryptH: Public key length %u\n", nbytes); + printf(" TPM_RSAPrivateDecryptH: Private key length %u\n", dbytes); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Public key", narr); + printf(" TPM_RSAPrivateDecryptH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Private key", darr); + /* decrypt with private key */ + rc = TPM_RSAPrivateDecrypt(decrypt_data, /* decrypted data */ + decrypt_data_length, /* length of data put into decrypt_data */ + decrypt_data_size, /* size of decrypt_data buffer */ + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + encrypt_data, /* encrypted data */ + encrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Decrypt data", decrypt_data, *decrypt_data_length); + } + return rc; +} + +/* TPM_RSAPublicEncryptSbuffer_Key() encrypts 'sbuffer' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, + TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_RSAPublicEncryptSbuffer_Key:\n"); + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* encrypt the serialization buffer with the public key, and place + the result in the enc_data buffer */ + rc = TPM_RSAPublicEncrypt_Key(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key); + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Key: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPublicEncrypt_Key: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_pubkey' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Pubkey: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_pubkey == NULL) { + printf("TPM_RSAPublicEncrypt_Pubkey: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_pubkey->algorithmParms.encScheme, + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key modulus and + exponent, and puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) + +{ + TPM_RESULT rc = 0; + unsigned char *encrypt_data = NULL; + + printf(" TPM_RSAPublicEncrypt_Common: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + TPM_PrintFourLimit(" TPM_RSAPublicEncrypt_Common: Decrypt data", decrypt_data, decrypt_data_size); + /* check the key size vs the data size */ + if (rc == 0) { + if (decrypt_data_size > nbytes) { + printf("TPM_RSAPublicEncrypt_Common: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + /* allocate an array for the encrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&encrypt_data, nbytes); + } + /* pad and encrypt the data */ + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Public key", narr); + printf(" TPM_RSAPublicEncrypt_Common: Exponent %02x %02x %02x\n", + earr[0], earr[1], earr[2]); + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + nbytes, /* encrypted data size */ + encScheme, /* encryption scheme */ + decrypt_data, /* decrypted data */ + decrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + /* copy the result to the sized buffer */ + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt_Common: Encrypt data size %u\n", nbytes); + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Encrypt data", encrypt_data); + rc = TPM_SizedBuffer_Set(enc_data, nbytes, encrypt_data); + } + free(encrypt_data); /* @1 */ + return rc; +} + +/* + Signing Functions + + These commands show the TPM command and the allowed signature schemes: + + SHA DER INFO + TPM_GetAuditDigestSigned y n y + TPM_CertifyKey y n y + TPM_CertifyKey2 y n y + TPM_CertifySelfTest y n y + TPM_Quote y n y + TPM_Quote2 y n y + TPM_Sign y y y + TPM_MakeIdentity y n y + TPM_GetCapabilitySigned y n y +*/ + +/* TPM_RSASignToSizedBuffer() signs 'message' using the private key in 'tpm_key' and places the + result in 'signature' + + 'signature' should be initialized and deleted by the caller +*/ + +TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *rsa_key_parms; + unsigned int signature_length; + + printf(" TPM_RSASignToSizedBuffer: Message size %lu bytes\n", (unsigned long)message_size); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(tpm_key->algorithmParms)); + } + /* allocating space for the signature */ + if (rc == 0) { + rc = TPM_SizedBuffer_Allocate(signature, (rsa_key_parms->keyLength)/CHAR_BIT); + } + /* sign */ + if (rc == 0) { + rc = TPM_RSASignH(signature->buffer, /* output signature */ + &signature_length, /* output, size of signature */ + signature->size, /* input, size of signature buffer */ + message, /* message */ + message_size, /* message size */ + tpm_key); /* input, signing key */ + } + /* sanity check on signature */ + if (rc == 0) { + if (signature_length != signature->size) { + printf("TPM_RSASignToSizedBuffer: Error (fatal) signature_length %u sigSize %u\n", + signature_length, signature->size); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + return rc; +} + + +/* TPM_RSASignH() signs 'message' using the private key in 'tpm_key'. 'signature_length' bytes are + moved to 'signature'. + + 'signature_length' is at most 'signature_size'. +*/ + +TPM_RESULT TPM_RSASignH(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSASignH: Message size %lu bytes\n", (unsigned long)message_size); + TPM_PrintFourLimit(" TPM_RSASignH: Message", message, message_size); + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSASignH: Public key", narr); + printf(" TPM_RSASignH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSASignH: Private key", darr); + /* sign with private key */ + rc = TPM_RSASign(signature, /* output */ + signature_length, /* output, size of signature */ + signature_size, /* input, size of signature buffer */ + tpm_key->algorithmParms.sigScheme, /* input, type of signature */ + message, /* input */ + message_size, /* input */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignH: Signature", signature); + } + return rc; +} + +/* TPM_RSAVerifyH() verifies 'message' using the TPM format public key in 'tpm_pubkey' +*/ + +TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, /* input */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + TPM_PUBKEY *tpm_pubkey) /* input, verify key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAVerifyH: Message size %u bytes\n", message_size); + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSAVerifyH: Public key", narr); + TPM_PrintAll(" TPM_RSAVerifyH: Public exponent", earr, ebytes); + /* verify with public key */ + rc = TPM_RSAVerify(signature->buffer, /* input signature buffer */ + signature->size, /* input, size of signature buffer */ + tpm_pubkey->algorithmParms.sigScheme, /* input, type of signature */ + message, /* message */ + message_size, /* message size */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + return rc; +} + +/* TPM_RSAVerify() verifies the 'signature' of size 'signature_size' on the 'message' of size + 'message_size' using the public key n,e and the signature scheme 'sigScheme' as specified in PKCS + #1 v2.0. +*/ + +TPM_RESULT TPM_RSAVerify(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAVerify:\n"); + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSAVerify: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSAVerifySHA1(signature, + signature_size, + message, + message_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + printf("TPM_RSAVerify: Error, sigScheme %04hx unsupported\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + default: + printf("TPM_RSAVerify: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + return rc; +} + +/* + OAEP Padding +*/ + +/* TPM_RSA_padding_add_PKCS1_OAEP() is a variation of the the openSSL function + + int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, unsigned char *p, int pl); + + It is used for TPM migration. The "encoding parameter" pl is replaced by pHash and the generated + random seed is replaced by a seed parameter. + + This function was independently written from the PKCS1 specification "9.1.1.1 Encoding + Operation", intended to be unencumbered by any license. + + + | seed | pHash | PS | 01 | Message | + + SHA1 SHA1 flen + + | <- emLen -> | + | db + | maskDb + | dbMask | + | seedMask + | maskSeed +*/ + +TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, + const unsigned char *from, uint32_t fLen, + const unsigned char *pHash, /* input 20 bytes */ + const unsigned char *seed) /* input 20 bytes */ +{ + TPM_RESULT rc = 0; + unsigned char *dbMask; + unsigned char *db; + unsigned char *maskedDb; + unsigned char *seedMask; + unsigned char *maskedSeed; + + printf(" TPM_RSA_padding_add_PKCS1_OAEP: fLen %d emLen %d\n", fLen, emLen); + TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: from", from, fLen); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: seed", seed); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for */ + /* the hash function (2^61-1 octets for SHA-1) then output "parameter */ + /* string too long" and stop. */ + /* NOTE Not done, pHash is input directly */ + /* 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop. */ + if (rc == 0) { + if (emLen < ((2 * TPM_DIGEST_SIZE) + 1 + fLen)) { + printf("TPM_RSA_padding_add_PKCS1_OAEP: Error, " + "message length %u too large for encoded length %u\n", fLen, emLen); + rc = TPM_ENCRYPT_ERROR; + } + } + /* 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero octets. The length of + PS may be 0. */ + /* NOTE Created directly in DB (step 5) */ + + /* 4. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + + /* 5. Concatenate pHash, PS, the message M, and other padding to form a data block DB as: DB = + pHash || PS || 01 || M */ + if (rc == 0) { + /* NOTE Since db is eventually maskedDb, part of em, create directly in em */ + db = em + TPM_DIGEST_SIZE; + memcpy(db, pHash, TPM_DIGEST_SIZE); /* pHash */ + memset(db + TPM_DIGEST_SIZE, 0, /* PS */ + emLen - fLen - (2 * TPM_DIGEST_SIZE) - 1); + /* PSlen = emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + 0x01 index = TPM_DIGEST_SIZE + PSlen + = TPM_DIGEST_SIZE + emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + = emlen - fLen - TPM_DIGEST_SIZE - 1 */ + db[emLen - fLen - TPM_DIGEST_SIZE - 1] = 0x01; + memcpy(db + emLen - fLen - TPM_DIGEST_SIZE, from, fLen); /* M */ + + /* 6. Generate a random octet string seed of length hLen. */ + /* NOTE seed is input directly */ + + /* 7. Let dbMask = MGF(seed, emLen-hLen). */ + rc = TPM_Malloc(&dbMask, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, emLen - TPM_DIGEST_SIZE, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 8. Let maskedDB = DB \xor dbMask. */ + /* NOTE Since maskedDB is eventually em, XOR directly to em */ + maskedDb = em + TPM_DIGEST_SIZE; + TPM_XOR(maskedDb, db, dbMask, emLen - TPM_DIGEST_SIZE); + + /* 9. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Since seedMask is eventually em, create directly to em */ + seedMask = em; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDb, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 10. Let maskedSeed = seed \xor seedMask. */ + /* NOTE Since maskedSeed is eventually em, create directly to em */ + maskedSeed = em; + TPM_XOR(maskedSeed, seed, seedMask, TPM_DIGEST_SIZE); + + /* 11. Let EM = maskedSeed || maskedDB. */ + /* NOTE Created directly in em */ + + /* 12. Output EM. */ + TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: em", em, emLen); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_padding_check_PKCS1_OAEP() is a variation of the openSSL function + + int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, int rsa_len, unsigned char *p, int pl); + + It is used for TPM key migration. In addition to the message 'to' and message length 'tlen', the + seed and 'pHash are returned. + + This function was independently written from the PKCS1 specification "9.1.1.2 Decoding + Operation", intended to be unencumbered by the any license. + + | seed | pHash | PS | 01 | Message | + SHA1 SHA1 + | <- emLen -> | + + | maskedSeed + | seedMask + | maskedDB + | db + | <- dbMask -> | + +*/ + +TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, + const unsigned char *em, uint32_t emLen, + unsigned char *pHash, /* output 20 bytes */ + unsigned char *seed) /* output 20 bytes */ +{ + TPM_RESULT rc = 0; + const unsigned char *maskedSeed; + const unsigned char *maskedDB; + uint32_t dbLen; + unsigned char *dbMask; + unsigned char *seedMask; + unsigned char *db; + size_t i; + + printf(" TPM_RSA_padding_check_PKCS1_OAEP: emLen %d tSize %d\n", emLen, tSize); + TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: em", em, emLen); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for the hash function (2^61-1 + octets for SHA-1) then output "parameter string too long" and stop. */ + /* NOTE There is no P input. pHash is calculated for the output, but no comparison is + performed. */ + + /* 2. If ||EM|| < 2hLen+1, then output "decoding error" and stop. */ + if (rc == 0) { + if (emLen < (2 * TPM_DIGEST_SIZE) + 1) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, encoded length %u too small\n", emLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* 3. Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining ||EM|| + - hLen octets. */ + maskedSeed = em; + maskedDB = em + TPM_DIGEST_SIZE; + dbLen = emLen - TPM_DIGEST_SIZE; + /* 4. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Created directly in seed */ + seedMask = seed; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDB, dbLen); + } + if (rc == 0) { + /* 5. Let seed = maskedSeed \xor seedMask. */ + TPM_XOR(seed, maskedSeed, seedMask, TPM_DIGEST_SIZE); + /* 6. Let dbMask = MGF(seed, ||EM|| - hLen). */ + rc = TPM_Malloc(&dbMask, dbLen); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, dbLen, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 7. Let DB = maskedDB \xor dbMask. */ + /* NOTE XOR back to dbMask, since dbMask no longer needed */ + db = dbMask; + TPM_XOR(db, maskedDB, dbMask, dbLen); + /* 8. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + /* 9. Separate DB into an octet string pHash' consisting of the first hLen octets of DB, + ... */ + memcpy(pHash, db, TPM_DIGEST_SIZE); + /* ... a (possibly empty) octet string PS consisting of consecutive zero octets following + pHash', and a message M as: DB = pHash' || PS || 01 || M */ + for (i = TPM_DIGEST_SIZE; i < dbLen; i++) { + if (db[i] != 0x00) { + break; /* skip the PS segment */ + } + } + /* If there is no 01 octet to separate PS from M, output "decoding error" and stop. */ + if (i == dbLen) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + if (db[i] != 0x01) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* 10. If pHash' does not equal pHash, output "decoding error" and stop. */ + /* NOTE No pHash input to compare */ + /* 11. Output M. */ + if (rc == 0) { + i++; /* skip the 0x01 to the beginning of the message M */ + *tLen = dbLen - i; + if (*tLen > tSize) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, tSize %u too small for message %u\n", + tSize, *tLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + memcpy(to, db + i, *tLen); + printf(" TPM_RSA_padding_check_PKCS1_OAEP: tLen %d \n", *tLen); + TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: to", to, *tLen); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: seed", seed); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_exponent_verify() validates the public exponent against a list of legal values. Some + values (e.g. even numbers) will have the key generator. +*/ + +TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent) +{ + TPM_RESULT rc = 0; + size_t i; + int found; + + static const unsigned long legalExponent[] = { 3,5,7,17,257,65537 }; + + for (i = 0, found = FALSE ; + !found && (i < (sizeof(legalExponent) / sizeof (unsigned long))) ; + i++) { + + if (exponent == legalExponent[i]) { + found = TRUE; + } + } + if (!found) { + printf("TPM_RSA_exponent_verify: Error, public exponent %lu is illegal\n", exponent ); + rc = TPM_BAD_KEY_PROPERTY; + } + return rc; +} + +/* SHA1 and HMAC test driver + + Returns TPM_FAILEDSELFTEST on error +*/ + +TPM_RESULT TPM_CryptoTest(void) +{ + TPM_RESULT rc = 0; + int not_equal; + TPM_BOOL valid; + + /* SHA1 */ + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + uint32_t actual_size; + + /* HMAC */ + unsigned char key2[] = {0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa}; + unsigned char expect2[] = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91,0xa3, + 0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1,0x75,0xd3}; + /* data 0xdd repeated 50 times */ + unsigned char data2[50]; + + /* oaep tests */ + const unsigned char oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + unsigned char pHash_in[TPM_DIGEST_SIZE]; + unsigned char pHash_out[TPM_DIGEST_SIZE]; + unsigned char seed_in[TPM_DIGEST_SIZE] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, + 0xf0,0xf1,0xf2,0xf3}; + unsigned char seed_out[TPM_DIGEST_SIZE]; + unsigned char oaep_in[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; + unsigned char oaep_pad[256]; + unsigned char oaep_out[8]; + uint32_t oeap_length; + + /* symmetric key with pad */ + TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data = NULL; /* opaque structure, freed @7 */ + unsigned char clrStream[64]; /* expected */ + unsigned char *encStream; /* encrypted */ + uint32_t encSize; + unsigned char *decStream; /* actual */ + uint32_t decSize; + + /* symmetric key ctr and ofb mode */ + TPM_SECRET symKey; + TPM_NONCE pad; /* CTR or IV */ + TPM_ENCAUTH symClear; + TPM_ENCAUTH symEnc; + TPM_ENCAUTH symDec; + + /* RSA encrypt and decrypt, sign and verify */ + unsigned char *n; /* public key - modulus */ + unsigned char *p; /* private key prime */ + unsigned char *q; /* private key prime */ + unsigned char *d; /* private key (private exponent) */ + unsigned char encrypt_data[2048/8]; /* encrypted data */ + unsigned char signature[2048/8]; /* signature; libtpms added */ + + printf(" TPM_CryptoTest:\n"); + encStream = NULL; /* freed @1 */ + decStream = NULL; /* freed @2 */ + n = NULL; /* freed @3 */ + p = NULL; /* freed @4 */ + q = NULL; /* freed @5 */ + d = NULL; /* freed @6 */ + + if (rc == 0) { + printf(" TPM_CryptoTest: Test 1 - SHA1 one part\n"); + rc = TPM_SHA1(actual, + sizeof(buffer1) - 1, buffer1, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 2 - SHA1 two parts\n"); + rc = TPM_SHA1(actual, + 16, buffer1, /* first 16 */ + sizeof(buffer1) - 17, buffer1 + 16, /* rest */ + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 2\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 3 - HMAC generate - one part\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 50, data2, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC generate - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect2); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC check - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Check(&valid, + expect2, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_CryptoTest: Error in test 4\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 5 - OAEP add and check\n"); + rc = TPM_SHA1(pHash_in, + sizeof(oaep_pad_str), oaep_pad_str, + 0, NULL); + } + if (rc == 0) { + rc = TPM_RSA_padding_add_PKCS1_OAEP(oaep_pad, sizeof(oaep_pad), + oaep_in, sizeof(oaep_in), + pHash_in, seed_in); + } + if (rc == 0) { + rc = TPM_RSA_padding_check_PKCS1_OAEP(oaep_out, &oeap_length, sizeof(oaep_out), + oaep_pad, sizeof(oaep_pad), + pHash_out, + seed_out); + } + if (rc == 0) { + if (oeap_length != sizeof(oaep_out)) { + printf("TPM_CryptoTest: Error in test 5, expect length %lu, actual length %u\n", + (unsigned long)sizeof(oaep_out), oeap_length); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(oaep_in, oaep_out, sizeof(oaep_out)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 oaep\n"); + TPM_PrintFour("\tin ", oaep_in); + TPM_PrintFour("\tout", oaep_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(pHash_in, pHash_out, sizeof(pHash_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 pHash\n"); + TPM_PrintFour("\tpHash_in ", pHash_in); + TPM_PrintFour("\tpHash_out", pHash_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(seed_in, seed_out, sizeof(seed_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 seed\n"); + TPM_PrintFour("\tseed_in ", seed_in); + TPM_PrintFour("\tseed_out", seed_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 6 - Symmetric key with PKCS pad test\n"); + /* allocate memory for the key token */ + rc = TPM_SymmetricKeyData_New(&tpm_symmetric_key_data); /* freed @7 */ + } + /* generate a key */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_GenerateKey(tpm_symmetric_key_data); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(clrStream, sizeof(clrStream)); + } + /* symmetric encrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Encrypt(&encStream, /* output, freed @1 */ + &encSize, /* output */ + clrStream, /* input */ + sizeof(clrStream), /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric decrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt(&decStream, /* output, freed by caller */ + &decSize, /* output */ + encStream, /* input */ + encSize, /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric compare */ + if (rc == 0) { + if (sizeof(clrStream) != decSize) { + printf("TPM_CryptoTest: Error in test 6, in %lu, out %u\n", + (unsigned long)sizeof(clrStream), decSize); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(clrStream, decStream, sizeof(clrStream)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 6\n"); + TPM_PrintFour("\tclear stream in", clrStream); + TPM_PrintFour("\tdecrypted stream", decStream); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 7 - Symmetric key with CTR mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate CTR */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 8 - Symmetric key with OFB mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate IV */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + /* RSA OAEP encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 9 - RSA encrypt with OAEP padding\n"); + /* generate a key */ + rc = TPM_RSAGenerateKeyPair(&n, /* public key - modulus */ + &p, /* private key prime */ + &q, /* private key prime */ + &d, /* private key (private exponent) */ + 2048, /* key size in bits */ + tpm_default_rsa_exponent, /* public exponent as an array */ + 3); + } + /* encrypt */ + if (rc == 0) { + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 9, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 9\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + /* RSA PKCS1 pad, encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 10 - RSA encrypt with PKCS padding\n"); + /* encrypt */ + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + /* decrypt */ + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + /* check length after padding removed */ + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 10, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + /* check data */ + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 10\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + +// libtpms added begin + + if (rc == 0) { + printf(" TPM_CryptoTest: Test 11a - RSA sign with PKCS1v15 padding\n"); + rc = TPM_RSASign(signature, + &actual_size, + sizeof(signature), + TPM_SS_RSASSAPKCS1v15_SHA1, + expect1, + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + rc = TPM_RSAVerify(signature, /* input signature buffer */ + sizeof(signature), /* input, size of signature buffer */ + TPM_SS_RSASSAPKCS1v15_SHA1, /* input, type of signature */ + expect1, /* message */ + sizeof(expect1), /* message size */ + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent,/* public exponent */ + 3); + } + +#if 0 + /* Verification with TPM_SS_RSASSAPKCS1v15_DER is not supported */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 11b - RSA sign with PKCS1v15_DER padding\n"); + rc = TPM_RSASign(signature, + &actual_size, + sizeof(signature), + TPM_SS_RSASSAPKCS1v15_DER, + expect1, + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + rc = TPM_RSAVerify(signature, /* input signature buffer */ + sizeof(signature), /* input, size of signature buffer */ + TPM_SS_RSASSAPKCS1v15_DER, /* input, type of signature */ + expect1, /* message */ + sizeof(expect1), /* message size */ + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent,/* public exponent */ + 3); + } +#endif // libtpms added end + + /* run library specific self tests as required */ + if (rc == 0) { + rc = TPM_Crypto_TestSpecific(); + } + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + free(encStream); /* @1 */ + free(decStream); /* @2 */ + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + TPM_SymmetricKeyData_Free(&tpm_symmetric_key_data); /* @7 */ + return rc; +} + +/* 13.5 TPM_Sign rev 111 + + The Sign command signs data and returns the resulting digital signature. + + The TPM does not allow TPM_Sign with a TPM_KEY_IDENTITY (AIK) because TPM_Sign can sign arbitrary + data and could be used to fake a quote. (This could have been relaxed to allow TPM_Sign with an + AIK if the signature scheme is _INFO For an _INFO key, the metadata prevents TPM_Sign from faking + a quote.) + + The TPM MUST support all values of areaToSignSize that are legal for the defined signature scheme + and key size. The maximum value of areaToSignSize is determined by the defined signature scheme + and key size. + + In the case of PKCS1v15_SHA1 the areaToSignSize MUST be TPM_DIGEST (the hash size of a sha1 + operation - see 8.5.1 TPM_SS_RSASSAPKCS1v15_SHA1). In the case of PKCS1v15_DER the maximum size + of areaToSign is k - 11 octets, where k is limited by the key size (see 8.5.2 + TPM_SS_RSASSAPKCS1v15_DER). +*/ + +TPM_RESULT TPM_Process_Sign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + digital signatures. */ + TPM_SIZED_BUFFER areaToSign; /* The value to sign */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle authorization + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization handle */ + TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus ; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_RSA_KEY_PARMS *rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_SIGN_INFO tpm_sign_info; + const unsigned char *S1_data; /* data to be signed */ + uint32_t S1_size; + TPM_DIGEST infoDigest; /* TPM_SIGN_INFO structure digest */ + TPM_STORE_BUFFER sbuffer; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_Sign: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&areaToSign); /* freed @1 */ + TPM_SignInfo_Init(&tpm_sign_info); /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sign: keyHandle %08x\n", keyHandle); + /* get areaToSignSize and areaToSign parameters */ + returnCode = TPM_SizedBuffer_Load(&areaToSign, &command, ¶mSize); /* freed @1 */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sign: Signing %u bytes\n", areaToSign.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_Sign: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Sign: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* 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, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. If the areaToSignSize is 0 the TPM returns TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size == 0) { + printf("TPM_Process_Sign: Error, areaToSignSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING or TPM_KEY_LEGACY, if not return + the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_SIGNING) && ((key->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Sign: Error, keyUsage %04hx is invalid\n", key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. The TPM verifies that the signature scheme and key size can properly sign the areaToSign + parameter. NOTE Done in 5. - 7.*/ + /* get key -> TPM_RSA_KEY_PARMS */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(key->algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + /* 5. If signature scheme is TPM_SS_RSASSAPKCS1v15_SHA1 then */ + if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1\n"); + /* a. Validate that areaToSignSize is 20 return TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size != TPM_DIGEST_SIZE) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be %u\n", + areaToSign.size, TPM_DIGEST_SIZE); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 6. Else if signature scheme is TPM_SS_RSASSAPKCS1v15_DER then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_DER\n"); + /* a. Validate that areaToSignSize is at least 11 bytes less than the key size, return + TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size > (((rsa_key_parms->keyLength)/CHAR_BIT) - 11)) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be 11-%u\n", + areaToSign.size, ((rsa_key_parms->keyLength)/CHAR_BIT)); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 7. else if signature scheme is TPM_SS_RSASSAPKCS1v15_INFO then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_INFO\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Create S2 a TPM_SIGN_INFO structure */ + /* NOTE: Done by TPM_SignInfo_Init() */ + /* b. Set S2 -> fixed to "SIGN" */ + memcpy(tpm_sign_info.fixed, "SIGN", TPM_SIGN_INFO_FIXED_SIZE); + /* c.i. If nonceOdd is not present due to an unauthorized command return + TPM_BAD_PARAMETER */ + if (tag == TPM_TAG_RQU_COMMAND) { + printf("TPM_Process_Sign: Error, TPM_SS_RSASSAPKCS1v15_INFO and no auth\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> replay to nonceOdd */ + TPM_Nonce_Copy(tpm_sign_info.replay, nonceOdd); + /* d. Set S2 -> dataLen to areaToSignSize */ + /* e. Set S2 -> data to areaToSign */ + returnCode = TPM_SizedBuffer_Copy(&(tpm_sign_info.data), &areaToSign); + } + /* f. Set S1 to the SHA-1(S2) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(infoDigest, + &tpm_sign_info, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + S1_size = TPM_DIGEST_SIZE; + S1_data = infoDigest; + } + } + /* 8. Else return TPM_INVALID_KEYUSAGE */ + else { + printf("TPM_Process_Sign: Error, sigScheme %04hx\n", key->algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 9. The TPM computes the signature, sig, using the key referenced by keyHandle using S1 as the + value to sign */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintAll("TPM_Process_Sign: Digest to sign", S1_data, S1_size); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + S1_data, /* message */ + S1_size, /* message size */ + key); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sign: 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; + /* 10. Return the computed signature in Sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&areaToSign); /* @1 */ + TPM_SignInfo_Delete(&tpm_sign_info); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + +/* 13.1 TPM_SHA1Start rev 96 + + This capability starts the process of calculating a SHA-1 digest. + + The exposure of the SHA-1 processing is a convenience to platforms in a mode that do not have + sufficient memory to perform SHA-1 themselves. As such the use of SHA-1 is restrictive on the + TPM. + + The TPM may not allow any other types of processing during the execution of a SHA-1 + session. There is only one SHA-1 session active on a TPM. The exclusivity of a SHA-1 + context is due to the relatively large volatile buffer it requires in order to hold the + intermediate results between the SHA-1 context commands. This buffer can be in + contradiction to other command needs. + + After the execution of SHA1Start, and prior to SHA1End, the receipt of any command other than + SHA1Update will cause the invalidation of the SHA-1 session. +*/ + +TPM_RESULT TPM_Process_SHA1Start(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 - none */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t maxNumBytes = TPM_SHA1_MAXNUMBYTES; /* Maximum number of bytes that can be sent + to TPM_SHA1Update. Must be a multiple of + 64 bytes. */ + + printf("TPM_Process_SHA1Start: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Start: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This capability prepares the TPM for a subsequent TPM_SHA1Update, TPM_SHA1Complete or + TPM_SHA1CompleteExtend command. The capability SHALL open a thread that calculates a SHA-1 + digest. + */ + if (returnCode == TPM_SUCCESS) { + if (transportInternal == NULL) { + tpm_state->transportHandle = 0; /* SHA-1 thread not within transport */ + } + else { + tpm_state->transportHandle = transportInternal->transHandle; /* SHA-1 thread within + transport */ + } + returnCode = TPM_SHA1InitCmd(&(tpm_state->sha1_context)); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Start: 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; + /* append maxNumBytes */ + returnCode = TPM_Sbuffer_Append32(response, maxNumBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 13.2 TPM_SHA1Update rev 114 + + This capability inputs complete blocks of data into a pending SHA-1 digest. At the end of the + process, the digest remains pending. +*/ + +TPM_RESULT TPM_Process_SHA1Update(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_SIZED_BUFFER hashData; /* Bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SHA1Update: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Update: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate complete blocks of data into the digest of an existing SHA-1 + thread. Only integral numbers of complete blocks (64 bytes each) can be processed. + */ + /* 1. If there is no existing SHA-1 thread, return TPM_SHA_THREAD */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->sha1_context == NULL) { + printf("TPM_Process_SHA1Update: Error, no existing SHA1 thread\n"); + returnCode = TPM_SHA_THREAD; + } + } + /* 2. If numBytes is not a multiple of 64 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1Update: numBytes %u bytes\n", hashData.size); + if ((hashData.size % 64) != 0) { + printf("TPM_Process_SHA1Update: Error, numBytes not integral number of blocks\n"); + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 3. If numBytes is greater than maxNumBytes returned by TPM_SHA1Start */ + if (returnCode == TPM_SUCCESS) { + if (hashData.size > TPM_SHA1_MAXNUMBYTES) { + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 4. Incorporate hashData into the digest of the existing SHA-1 thread. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1UpdateCmd(tpm_state->sha1_context, hashData.buffer, hashData.size); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Update: 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.3 TPM_SHA1Complete rev 87 + + This capability terminates a pending SHA-1 calculation. +*/ + +TPM_RESULT TPM_Process_SHA1Complete(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_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST hashValue; /* The output of the SHA-1 hash. */ + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + + printf("TPM_Process_SHA1Complete: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Complete: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate a partial or complete block of data into the digest of an + existing SHA-1 thread, and terminate that thread. hashDataSize MAY have values in the range + of 0 through 64, inclusive. If the SHA-1 thread has received no bytes the TPM SHALL + calculate the SHA-1 of the empty buffer. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(hashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Complete: 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; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, hashValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.4 TPM_SHA1CompleteExtend rev 109 + + This capability terminates a pending SHA-1 calculation and EXTENDS the result into a Platform + Configuration Register using a SHA-1 hash process. + + This command is designed to complete a hash sequence and extend a PCR in memory-less + environments. + + This command SHALL incorporate a partial or complete block of data into the digest of an existing + SHA-1 thread, EXTEND the resultant digest into a PCR, and terminate the thread. hashDataSize MAY + have values in the range of 0 through 64, inclusive. +*/ + +TPM_RESULT TPM_Process_SHA1CompleteExtend(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_PCRINDEX pcrNum; /* Index of the PCR to be modified */ + TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST h1HashValue; /* The output of the SHA-1 hash. */ + TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ + + printf("TPM_Process_SHA1CompleteExtend: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrNum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); + } + /* get hashData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum); + returnCode = TPM_SizedBuffer_Load(&hashData, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1CompleteExtend: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. 1.Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ + /* 2. Map V1 to TPM_STANY_DATA */ + /* 3. Map L1 to V1 -> localityModifier */ + /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> pcrAttrib + [PCRIndex]. pcrExtendLocal, return TPM_BAD_LOCALITY */ + /* NOTE Done in TPM_ExtendCommon() */ + /* 5. Create H1 the TPM_DIGEST of the SHA-1 session ensuring that hashData, if any, is */ + /* added to the SHA-1 session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(h1HashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* 6. Perform the actions of TPM_Extend using H1 as the data and pcrNum as the PCR to extend */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, h1HashValue); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1CompleteExtend: 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; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, h1HashValue); + } + /* append outDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* TPM_SHA1CompleteCommon() is common code for TPM_Process_SHA1Complete() and + TPM_Process_SHA1CompleteExtend() +*/ + +TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, /* output: digest */ + void **sha1_context, /* IO: SHA1 context */ + TPM_SIZED_BUFFER *hashData) /* final data to be hashed */ +{ + TPM_RESULT rc = 0; + + /* The TPM specification says that the last data chunk must be 0-64 bytes */ + printf("TPM_SHA1CompleteCommon: %u bytes\n", hashData->size); + if (rc == 0) { + if (hashData->size > 64) { + printf("TPM_SHA1CompleteCommon: Error, hashDataSize %u not 0-64\n", + hashData->size); + rc = TPM_SHA_ERROR; + } + } + /* cannot call SHA1Complete() before SHA1Start() */ + if (rc == 0) { + if (*sha1_context == NULL) { + printf("TPM_SHA1CompleteCommon: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if ((rc == 0) && (hashData->size != 0)) { + rc = TPM_SHA1UpdateCmd(*sha1_context, hashData->buffer, hashData->size); + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(hashValue, *sha1_context); + } + /* the SHA1 thread should be terminated even if there is an error */ + TPM_SHA1Delete(sha1_context); + return rc; +} + +/* 13.6 TPM_GetRandom rev 87 + + GetRandom returns the next bytesRequested bytes from the random number generator to the caller. + + It is recommended that a TPM implement the RNG in a manner that would allow it to return RNG + bytes such that the frequency of bytesRequested being more than the number of bytes available is + an infrequent occurrence. +*/ + +TPM_RESULT TPM_Process_GetRandom(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 */ + uint32_t bytesRequested; /* Number of bytes to return */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER randomBytes; /* The returned bytes */ + + printf("TPM_Process_GetRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&randomBytes); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get bytesRequested parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bytesRequested, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM determines if amount bytesRequested is available from the TPM. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetRandom: bytesRequested %u\n", bytesRequested); + if (bytesRequested > TPM_RANDOM_MAX) { + bytesRequested = TPM_RANDOM_MAX; + printf("TPM_Process_GetRandom: bytes available %u\n", bytesRequested); + } + } + /* 2. Set randomBytesSize to the number of bytes available from the RNG. This number MAY be less + than bytesRequested. */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_SizedBuffer_Allocate(&randomBytes, bytesRequested); + } + /* 3. Set randomBytes to the next randomBytesSize bytes from the RNG */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_Random(randomBytes.buffer, bytesRequested); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetRandom: 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; + /* append randomBytes */ + returnCode = TPM_SizedBuffer_Store(response, &randomBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&randomBytes); /* freed @1 */ + return rcf; +} + +/* 13.7 TPM_StirRandom rev 109 + + StirRandom adds entropy to the RNG state. +*/ + +TPM_RESULT TPM_Process_StirRandom(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_SIZED_BUFFER inData; /* Data to add entropy to RNG state, + Number of bytes of input */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_StirRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_StirRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If dataSize is not less than 256 bytes, the TPM MAY return TPM_BAD_PARAMETER. */ + /* The TPM updates the state of the current RNG using the appropriate mixing function. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StirRandomCmd(&inData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_StirRandom: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + return rcf; +} + +/* 13.8 TPM_CertifyKey rev 107 + + The TPM_CertifyKey operation allows one key to certify the public portion of another key. A TPM + identity key may be used to certify non-migratable keys but is not permitted to certify migratory + keys or certified migration keys. As such, it allows the TPM to make the statement "this key is + held in a TPM-shielded location, and it will never be revealed." For this statement to have + veracity, the Challenger must trust the policies used by the entity that issued the identity and + the maintenance policy of the TPM manufacturer. + + Signing and legacy keys may be used to certify both migratable and non-migratable keys. Then the + usefulness of a certificate depends on the trust in the certifying key by the recipient of the + certificate. + + The key to be certified must be loaded before TPM_CertifyKey is called. + + The determination to use the TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 on the output is based on + which PCRs and what localities the certified key is restricted to. A key to be certified that + does not have locality restrictions and which uses no PCRs greater than PCR #15 will cause this + command to return and sign a TPM_CERTIFY_INFO structure, which provides compatibility with V1.1 + TPMs. + + When this command is run to certify all other keys (those that use PCR #16 or higher, as well as + those limited by locality in any way), it will return and sign a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey does not support the case where (a) the certifying key requires a usage + authorization to be provided but (b) the key-to-be-certified does not. In such cases, + TPM_CertifyKey2 must be used. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be TPM_AUTH_NEVER for + this key) and the incoming session data is used for the second auth session in the list. In + TPM_CertifyKey, the first session is the certifying key and the second session is the + key-to-be-certified. In TPM_CertifyKey2, the first session is the key-to-be-certified and the + second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey(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 certHandle; /* Handle of the key to be used to certify the key. */ + TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* The authorization session digest for inputs and + certHandle. HMAC key: certKey.auth. */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_BOOL pcrUsage; + TPM_LOCALITY_SELECTION localityAtRelease; + int v1Version; /* TPM 1.1 or TPM 1.2 */ + int certifyType = 0; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 */ + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* 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; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 structure + that provides information relative to keyhandle + NOTE This is c1 in the Actions. */ + TPM_CERTIFY_INFO2 certifyInfo2; + TPM_SIZED_BUFFER outData; /* The signature of certifyInfo */ + + printf("TPM_Process_CertifyKey: Ordinal Entry\n"); + TPM_CertifyInfo_Init(&certifyInfo); /* freed @1 */ + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + /* + get inputs + */ + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &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_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey: certAuthHandle %08x\n", certAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey: keyAuthHandle %08x\n", keyAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey: 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) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error. */ + + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If keyHandle -> payload is not TPM_PT_ASYM, return TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (targetKey->tpm_store_asymkey->payload != TPM_PT_ASYM) { + printf("TPM_Process_CertifyKey: Error, target key invalid payload %02x\n", + targetKey->tpm_store_asymkey->payload); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyflags -> keyInfo -> migratable is TRUE return TPM_MIGRATEFAIL */ + if (targetKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CertifyKey: Error, target key is migratable\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 5. Validate that certHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, + if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle -> keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, certHandle -> keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate that keyHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If keyHandle -> digestAtRelease requires the use of PCRs 16 or higher to calculate or if + keyHandle -> localityAtRelease is not 0x1F */ + /* get PCR usage 16 and higher */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetPCRUsage(&pcrUsage, targetKey, 2); + } + /* get localityAtRelease */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetLocalityAtRelease(&localityAtRelease, targetKey); + } + if (returnCode == TPM_SUCCESS) { + if (pcrUsage || (localityAtRelease != TPM_LOC_ALL)) { + /* a. Set V1 to 1.2 */ + v1Version = 2; /* locality or >2 PCR's */ + } + /* 8. Else */ + else { + /* a. Set V1 to 1.1 */ + v1Version = 1; /* no locality and <= 2 PCR's */ + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: V1 %d\n", v1Version); + /* 9. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey: Setting PCR info from key\n"); + /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and + compare to keyHandle -> digestAtRelease and if a mismatch return + TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + /* b. If V1 is 1.1 */ + if (v1Version == 1) { + certifyType = 1; + /* i. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. The TPM MUST set c1 -> pcrInfoSize to 44. */ + /* iv. The TPM MUST set c1 -> pcrInfo to a TPM_PCR_INFO structure properly filled + out using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_CreateFromKey(&(certifyInfo.tpm_pcr_info), + targetKey); + } + /* v. The TPM MUST set c1 -> digestAtCreation to 20 bytes of 0x00. */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Init(certifyInfo.tpm_pcr_info->digestAtCreation); + } + } + /* c. Else */ + else { + certifyType = 2; + /* i. Create C1 a TPM_CERTIFY_INFO2 structure */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. Set C1 -> pcrInfoSize to the size of an appropriate TPM_PCR_INFO_SHORT + structure. */ + /* iv. Set C1 -> pcrInfo to a properly filled out TPM_PCR_INFO_SHORT structure, + using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* v. Set C1 -> migrationAuthoritySize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + } + /* 10. Else */ + else { + certifyType = 1; + /* a. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* b. Fill in C1 with the information from the key pointed to be keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* c. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + } + } + /* 11. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + <key> is the actual public modulus, and does not include any structure formatting. */ + /* 12. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo_Set() or TPM_CertifyInfo2_Set() */ + /* 13. The TPM copies the antiReplay parameter to c1 -> data. */ + /* Set C1 -> parentPCRStatus to the value from keyHandle NOTE: Implied in specification */ + /* Fill in C1 with the information from the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Setting certifyInfo from target key\n"); + if (certifyType == 1) { + TPM_Digest_Copy(certifyInfo.data, antiReplay); + certifyInfo.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo_Set(&certifyInfo, targetKey); + } + else { + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + certifyInfo2.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + } + /* 14. The TPM sets certifyInfo to C1. */ + /* NOTE Created as certifyInfo or certifyInfo2 */ + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Digesting certifyInfo\n"); + if (certifyType == 1) { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store); + } + else { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Signing certifyInfo digest with certifying key\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey: 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 */ + if (certifyType == 1) { + returnCode = TPM_CertifyInfo_Store(response, &certifyInfo); + } + else { + returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); + } + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + 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) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *certHmacKey, /* HMAC key */ + cert_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* 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)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo_Delete(&certifyInfo); /* @1 */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + return rcf; +} + +/* 13.9 TPM_CertifyKey2 rev 107 + + This command is based on TPM_CertifyKey, but includes the ability to certify a Certifiable + Migration Key (CMK), which requires extra input parameters. + + TPM_CertifyKey2 always produces a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey2 does not support the case where (a) the key-to-be-certified requires a usage + authorization to be provided but (b) the certifying key does not. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be + TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER for this key) and the incoming session data is used for + the second auth session in the list. In TPM_CertifyKey2, the first session is the key to be + certified and the second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ + TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ + TPM_DIGEST migrationPubDigest; /* The digest of a TPM_MSA_COMPOSITE structure, + containing at least one public key of a Migration + Authority */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. HMAC key: key.usageAuth. */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* Authorization HMAC key: certKey.auth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_STORE_ASYMKEY *targetStoreAsymkey; + TPM_CMK_MIGAUTH m2CmkMigauth; + TPM_BOOL hmacValid; + TPM_DIGEST migrationAuthority; + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO2 certifyInfo2; /* TPM_CERTIFY_INFO2 relative to keyHandle */ + TPM_SIZED_BUFFER outData; /* The signed public key. */ + + printf("TPM_Process_CertifyKey2: Ordinal Entry\n"); + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @3 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle); + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle %08x\n", certHandle); + /* get the migrationPubDigest parameter */ + returnCode = TPM_Digest_Load(migrationPubDigest, &command, ¶mSize); + } + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &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_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey2: keyAuthHandle %08x\n", keyAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey2: certAuthHandle %08x\n", certAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey2: 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) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the keys corresponding to the certHandle and keyHandle parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the TPM_STORE_ASYMKEY cache for the target TPM_KEY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&targetStoreAsymkey, targetKey); + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey2: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values: */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey2: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If the command is TPM_TAG_RQU_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey2: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyFlags -> migratable is TRUE and + [keyHandle -> keyFlags-> migrateAuthority is FALSE or + (keyHandle -> payload != TPM_PT_MIGRATE_RESTRICTED and + keyHandle -> payload != TPM_PT_MIGRATE_EXTERNAL)] + return TPM_MIGRATEFAIL */ + if ((targetKey->keyFlags & TPM_MIGRATABLE) && + (!(targetKey->keyFlags & TPM_MIGRATEAUTHORITY) || + ((targetStoreAsymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + (targetStoreAsymkey->payload != TPM_PT_MIGRATE_EXTERNAL)))) { + printf("TPM_Process_CertifyKey2: Error, target key migrate fail\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 4. Validate that certHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle ->keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. The TPM SHALL create a c1 a TPM_CERTIFY_INFO2 structure from the key pointed to by + keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + /* 7. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + <key> is the actual public modulus, and does not include any structure formatting. */ + /* 8. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + if (returnCode == TPM_SUCCESS) { + /* 9. Copy the antiReplay parameter to c1 -> data */ + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + /* 10. Copy other keyHandle parameters into C1 */ + certifyInfo2.parentPCRStatus = targetPCRStatus; + /* 11. If keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ + if ((targetStoreAsymkey->payload == TPM_PT_MIGRATE_RESTRICTED) || + (targetStoreAsymkey->payload == TPM_PT_MIGRATE_EXTERNAL)) { + printf("TPM_Process_CertifyKey2: " + "TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. create thisPubKey, a TPM_PUBKEY structure containing the public key, algorithm and + parameters corresponding to keyHandle */ + /* NOTE Not required. Digest is created directly below */ + /* b. Verify that the migration authorization is valid for this key */ + /* i. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set M2 -> msaDigest to migrationPubDigest */ + TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationPubDigest ); + /* iii. Set M2 -> pubKeyDigest to SHA-1[thisPubKey] */ + returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, targetKey); + } + /* iv. Verify that [keyHandle -> migrationAuth] == HMAC(M2) signed by using tpmProof as + the secret and return error TPM_MA_SOURCE on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Check migrationAuth\n"); + returnCode = + TPM_CmkMigauth_CheckHMAC(&hmacValid, /* result */ + targetStoreAsymkey->migrationAuth, /* expect */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth); + } + if (returnCode == TPM_SUCCESS) { + if (!hmacValid) { + printf("TPM_Process_CertifyKey2: Error, Invalid migrationAuth\n"); + returnCode = TPM_MA_SOURCE; + } + } + /* c. Set C1 -> migrationAuthority = SHA-1(migrationPubDigest || keyHandle -> payload) + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Set migrationAuthority\n"); + returnCode = TPM_SHA1(migrationAuthority, + TPM_DIGEST_SIZE, migrationPubDigest, + sizeof(TPM_PAYLOAD_TYPE), &(targetStoreAsymkey->payload), + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&(certifyInfo2.migrationAuthority), + TPM_DIGEST_SIZE, migrationAuthority); + } + /* d. if keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_RESTRICTED */ + /* e. if keyHandle -> payload == TPM_PT_MIGRATE_EXTERNAL */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_EXTERNAL */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + } + /* 12. Else */ + else { + printf("TPM_Process_CertifyKey2: " + " Not TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. set C1 -> migrationAuthority = NULL */ + /* b. set C1 -> migrationAuthoritySize = 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* c. Set C1 -> payloadType = TPM_PT_ASYM */ + certifyInfo2.payloadType = TPM_PT_ASYM; + } + } + if (returnCode == TPM_SUCCESS) { + /* 13. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey2: Setting PCR info from key\n"); + /* a. The TPM MUST set c1 -> pcrInfoSize to match the pcrInfoSize from the keyHandle + key. */ + /* b. The TPM MUST set c1 -> pcrInfo to match the pcrInfo from the keyHandle key */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* c. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and compare to + keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + } + /* 14. Else */ + /* a. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Digesting certifyInfo\n"); + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey2: 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_CertifyInfo2_Store(response, &certifyInfo2); + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + 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) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *certHmacKey, /* HMAC key */ + cert_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)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @3 */ + return rcf; +} + +/* 28.3 TPM_CertifySelfTest rev 94 + + CertifySelfTest causes the TPM to perform a full self-test and return an authenticated value if + the test passes. + + If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM + and the caller have AuthData. + + If a caller requires proof for a third party, the signing key must be one whose signature is + trusted by the third party. A TPM-identity key may be suitable. + + Information returned by TPM_CertifySelfTest MUST NOT aid identification of an individual TPM. +*/ + +TPM_RESULT TPM_Process_CertifySelfTest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + digital signatures. */ + TPM_NONCE antiReplay; /* AntiReplay nonce to prevent replay of messages */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the + inputs and use of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey; /* from keyHandle */ + TPM_BOOL sigKeyPCRStatus; + TPM_SECRET *sigKeyUsageAuth; + TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ + TPM_DIGEST m2Digest; /* message to sign */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_CertifySelfTest: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &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, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifySelfTest: 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 perform TPM_SelfTestFull. If the test fails the TPM returns the appropriate + error code. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Running self test\n"); + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* 2. After successful completion of the self-test the TPM then validates the authorization to + use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &sigKeyPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifySelfTest: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&sigKeyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + sigKeyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the command parameters using privAuth */ + 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 */ + } + /* a. If the key pointed to by keyHandle has a signature scheme that is not + TPM_SS_RSASSAPKCS1v15_SHA1, the TPM may either return TPM_BAD_SCHEME or may return + TPM_SUCCESS and a vendor specific signature. */ + if (returnCode == TPM_SUCCESS) { + if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_CertifySelfTest: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_SCHEME; + } + } + /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or + TPM_KEY_IDENTITY. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_LEGACY) && + (sigKey->keyUsage != TPM_KEY_IDENTITY)) { + printf("TPM_Process_CertifySelfTest: Error, Illegal keyUsage %04hx\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create t1 the NOT null terminated string of "Test Passed" */ + /* 4. The TPM creates m2 the message to sign by concatenating t1 || AntiReplay || ordinal. */ + if (returnCode == TPM_SUCCESS) { + nOrdinal = htonl(ordinal); + returnCode = TPM_SHA1(m2Digest, + sizeof("Test Passed") - 1, "Test Passed", + TPM_NONCE_SIZE, antiReplay, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + /* 5. The TPM signs the SHA-1 of m2 using the key identified by keyHandle, and returns the + signature as sig. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + m2Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifySelfTest: 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 sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&sig); /* @1 */ + return rcf; +} diff --git a/src/tpm12/tpm_cryptoh.h b/src/tpm12/tpm_cryptoh.h new file mode 100644 index 0000000..268df6c --- /dev/null +++ b/src/tpm12/tpm_cryptoh.h @@ -0,0 +1,362 @@ +/********************************************************************************/ +/* */ +/* High Level Platform Independent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_cryptoh.h 4300 2011-01-18 18:00:27Z 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. */ +/********************************************************************************/ + +#ifndef TPM_CRYPTOH_H +#define TPM_CRYPTOH_H + +#include "tpm_global.h" +#include "tpm_types.h" +#include "tpm_sizedbuffer.h" +#include "tpm_structures.h" + +/* + TPM_SIGN_INFO +*/ + +void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info); +TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIGN_INFO *tpm_sign_info); +void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info); + +/* + TPM_CERTIFY_INFO +*/ + +void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info); +#if 0 +TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO *tpm_certify_info); +void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info); + +TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, + TPM_KEY *tpm_key); + +/* + TPM_CERTIFY_INFO2 +*/ + +void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2); +#if 0 +TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO2 *tpm_certify_info2); +void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2); + +TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, + TPM_KEY *tpm_key); + +/* + TPM_SYMMETRIC_KEY +*/ + +void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key); +TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY *tpm_symmetric_key); +void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key); + +TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, + TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_data); +TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size); + +/* + RSA functions +*/ + + +TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, + uint32_t *decrypt_data_length, + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, + uint32_t *decrypt_data_length, + uint32_t decrypt_data_size, + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, + TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key); +TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_KEY *tpm_key); +TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +TPM_RESULT TPM_RSASignH(unsigned char *signature, + unsigned int *signature_length, + unsigned int signature_size, + const unsigned char *message, + size_t message_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, + const unsigned char *message, + size_t message_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, + const unsigned char *message, + uint32_t message_size, + TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_RSAVerify(unsigned char *signature, + unsigned int signature_size, + TPM_SIG_SCHEME sigScheme, + const unsigned char *message, + uint32_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent); + +/* + OAEP Padding +*/ + +TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, + const unsigned char *from, uint32_t fLen, + const unsigned char *pHash, + const unsigned char *seed); +TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, + const unsigned char *em, uint32_t emLen, + unsigned char *pHash, + unsigned char *seed); + +/* + Digest functions - SHA-1 and HMAC +*/ + +TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...); +TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...); +TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error); + +TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + ...); + +TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET key, + ...); +TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, + void *structure, + TPM_HMAC expect, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error); + +/* + XOR +*/ + +void TPM_XOR(unsigned char *out, + const unsigned char *in1, + const unsigned char *in2, + size_t length); + +/* + MGF1 +*/ + +TPM_RESULT TPM_MGF1(unsigned char *array, + uint32_t arrayLen, + const unsigned char *seed, + uint32_t seedLen); +TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, + uint32_t arrayLen, + uint32_t seedLen, + ...); +/* bignum */ + +TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, + unsigned int *bytes, + TPM_BIGNUM bn_in, + uint32_t padBytes); +TPM_RESULT TPM_bn2binArray(unsigned char *bin, + unsigned int bytes, + TPM_BIGNUM bn); +TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, + const unsigned char *bin0, uint32_t size0, + const unsigned char *bin1, uint32_t size1); + +/* + Self Test +*/ + +TPM_RESULT TPM_CryptoTest(void); + + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_Sign(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 TPM_Process_SHA1Start(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 TPM_Process_SHA1Update(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 TPM_Process_SHA1Complete(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 TPM_Process_SHA1CompleteExtend(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 TPM_Process_GetRandom(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 TPM_Process_StirRandom(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 TPM_Process_CertifyKey(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 TPM_Process_CertifyKey2(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 TPM_Process_CertifySelfTest(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); + + +#endif diff --git a/src/tpm12/tpm_daa.c b/src/tpm12/tpm_daa.c new file mode 100644 index 0000000..7c0056e --- /dev/null +++ b/src/tpm12/tpm_daa.c @@ -0,0 +1,5729 @@ +/********************************************************************************/ +/* */ +/* DAA Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_daa.c 4768 2017-07-28 13:19:28Z 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_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_sizedbuffer.h" + +#include "tpm_daa.h" + +/* + TPM_DAA_SESSION_DATA (the entire array) +*/ + +void TPM_DaaSessions_Init(TPM_DAA_SESSION_DATA *daaSessions) +{ + size_t i; + + printf(" TPM_DaaSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + TPM_DaaSessionData_Init(&(daaSessions[i])); + } + return; +} + +/* TPM_DaaSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DaaSessions_Init() +*/ + +TPM_RESULT TPM_DaaSessions_Load(TPM_DAA_SESSION_DATA *daaSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_DaaSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + if (rc == 0) { + if (activeCount > TPM_MIN_DAA_SESSIONS) { + printf("TPM_DaaSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_DAA_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_DaaSessions_Load: Loading %u sessions\n", activeCount); + } + /* load DAA sessions */ + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_DaaSessionData_Load(&(daaSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_DaaSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaaSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; + uint32_t activeCount; + + /* store active count */ + if (rc == 0) { + TPM_DaaSessions_GetSpace(&space, daaSessions); + activeCount = TPM_MIN_DAA_SESSIONS - space; + printf(" TPM_DaaSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store DAA sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_DAA_SESSIONS) ; i++) { + if ((daaSessions[i]).valid) { /* if the session is active */ + rc = TPM_DaaSessionData_Store(sbuffer, &(daaSessions[i])); + } + } + return rc; +} + +/* TPM_DaaSessions_Delete() terminates all loaded DAA sessions + +*/ + +void TPM_DaaSessions_Delete(TPM_DAA_SESSION_DATA *daaSessions) +{ + size_t i; + + printf(" TPM_DaaSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + TPM_DaaSessionData_Delete(&(daaSessions[i])); + } + return; +} + +/* TPM_DaaSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_DaaSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_DAA_SESSION_DATA *daaSessions) +{ + printf(" TPM_DaaSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_DAA_SESSIONS ; (*index)++) { + if (!((daaSessions[*index]).valid)) { + printf(" TPM_DaaSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_DaaSessions_GetSpace() returns the number of unused daaHandle's. + +*/ + +void TPM_DaaSessions_GetSpace(uint32_t *space, + TPM_DAA_SESSION_DATA *daaSessions) +{ + uint32_t i; + + printf(" TPM_DaaSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + if (!((daaSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_DaaSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_DaaSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_DaaSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_DaaSessions_GetSpace(&space, daaSessions); + /* store loaded handle count. Safe case because of TPM_MIN_DAA_SESSIONS value */ + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_DAA_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_DAA_SESSIONS) ; i++) { + if ((daaSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (daaSessions[i]).daaHandle); /* store it */ + } + } + return rc; +} + +/* TPM_DaaSessions_GetNewHandle() checks for space in the DAA sessions table. + + If there is space, it returns a TPM_DAA_SESSION_DATA entry in 'tpm_daa_session_data' and its + handle in 'daaHandle'. The entry is marked 'valid'. + + If *daaHandle non-zero, the suggested value is tried first. + + Returns TPM_RESOURCES if there is no space in the sessions table. +*/ + +TPM_RESULT TPM_DaaSessions_GetNewHandle(TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* entry */ + TPM_HANDLE *daaHandle, + TPM_BOOL *daaHandleValid, + TPM_DAA_SESSION_DATA *daaSessions) /* array */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_DaaSessions_GetNewHandle:\n"); + *daaHandle = FALSE; + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_DaaSessions_IsSpace(&isSpace, /* TRUE if space available */ + &index, /* if space available, index into array */ + daaSessions); /* array */ + if (!isSpace) { + printf("TPM_DaaSessions_GetNewHandle: Error, no space in daaSessions table\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(daaHandle, /* I/O, pointer to handle */ + daaSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_DaaSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_DaaSessions_GetNewHandle: Assigned handle %08x\n", *daaHandle); + *tpm_daa_session_data = &(daaSessions[index]); + TPM_DaaSessionData_Init(*tpm_daa_session_data); /* should be redundant since + terminate should have done + this */ + (*tpm_daa_session_data)->daaHandle = *daaHandle; + (*tpm_daa_session_data)->valid = TRUE; + *daaHandleValid = TRUE; + } + return rc; +} + +/* TPM_DaaSessions_GetEntry() searches all entries for the entry matching the handle, and + returns the TPM_DAA_SESSION_DATA entry associated with the handle. + + Returns + 0 for success + TPM_BAD_HANDLE if the handle is not found +*/ + +TPM_RESULT TPM_DaaSessions_GetEntry(TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* session for + daaHandle */ + TPM_DAA_SESSION_DATA *daaSessions, /* points to first session in + array */ + TPM_HANDLE daaHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_DaaSessions_GetEntry: daaHandle %08x\n", daaHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_DAA_SESSIONS) && !found ; i++) { + if ((daaSessions[i].valid) && + (daaSessions[i].daaHandle == daaHandle)) { /* found */ + found = TRUE; + *tpm_daa_session_data = &(daaSessions[i]); + } + } + if (!found) { + printf(" TPM_DaaSessions_GetEntry: session handle %08x not found\n", + daaHandle); + rc = TPM_BAD_HANDLE; + } + return rc; +} + +/* TPM_DaaSessions_AddEntry() adds an TPM_DAA_SESSION_DATA object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_DaaSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_DAA_SESSION_DATA *daaSessions, /* input */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_DaaSessions_AddEntry:\n"); + /* check for valid TPM_DAA_SESSION_DATA */ + if (rc == 0) { + if (tpm_daa_session_data == NULL) { /* NOTE: should never occur */ + printf("TPM_DaaSessions_AddEntry: Error (fatal), NULL TPM_DAA_SESSION_DATA\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_DaaSessions_IsSpace(&isSpace, &index, daaSessions); + if (!isSpace) { + printf("TPM_DaaSessions_AddEntry: Error, session entries full\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + daaSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_DaaSessions_GetEntry); + } + if (rc == 0) { + TPM_DaaSessionData_Copy(&(daaSessions[index]), *tpm_handle, tpm_daa_session_data); + daaSessions[index].valid = TRUE; + printf(" TPM_DaaSessions_AddEntry: Index %u handle %08x\n", + index, daaSessions[index].daaHandle); + } + return rc; +} + +/* TPM_DaaSessions_TerminateHandle() terminates the session associated with 'daaHandle'. + +*/ + +TPM_RESULT TPM_DaaSessions_TerminateHandle(TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle) +{ + TPM_RESULT rc = 0; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; + + printf(" TPM_DaaSessions_TerminateHandle: daaHandle %08x\n", daaHandle); + /* get the TPM_DAA_SESSION_DATA associated with the TPM_HANDLE */ + if (rc == 0) { + rc = TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + daaSessions, /* array */ + daaHandle); + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + return rc; +} + +/* + TPM_DAA_SESSION_DATA (one element of the array) +*/ + +/* TPM_DaaSessionData_Init() initializes the DAA session. + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DaaSessionData_Init(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + printf(" TPM_DaaSessionData_Init:\n"); + TPM_DAAIssuer_Init(&(tpm_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Init(&(tpm_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Init(&(tpm_daa_session_data->DAA_session)); + TPM_DAAJoindata_Init(&(tpm_daa_session_data->DAA_joinSession)); + tpm_daa_session_data->daaHandle = 0; + tpm_daa_session_data->valid = FALSE; + return; +} + +/* TPM_DaaSessionData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DaaSessionData_Init() + After use, call TPM_DaaSessionData_Delete() to free memory +*/ + +TPM_RESULT TPM_DaaSessionData_Load(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_Load:\n"); + /* load DAA_issuerSettings */ + if (rc == 0) { + rc = TPM_DAAIssuer_Load(&(tpm_daa_session_data->DAA_issuerSettings), stream, stream_size); + } + /* load DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Load(&(tpm_daa_session_data->DAA_tpmSpecific), stream, stream_size); + } + /* load DAA_session */ + if (rc == 0) { + rc = TPM_DAAContext_Load(&(tpm_daa_session_data->DAA_session),stream, stream_size); + } + /* load DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Load(&(tpm_daa_session_data->DAA_joinSession), stream, stream_size); + } + /* load daaHandle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_session_data->daaHandle), stream, stream_size); + } + /* set valid */ + if (rc == 0) { + tpm_daa_session_data->valid = TRUE; + } + return rc; +} + +/* TPM_DaaSessionData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaaSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_Store:\n"); + /* store DAA_issuerSettings */ + if (rc == 0) { + rc = TPM_DAAIssuer_Store(sbuffer, &(tpm_daa_session_data->DAA_issuerSettings)); + } + /* store DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Store(sbuffer, &(tpm_daa_session_data->DAA_tpmSpecific)); + } + /* store DAA_session */ + if (rc == 0) { + rc = TPM_DAAContext_Store(sbuffer, &(tpm_daa_session_data->DAA_session)); + } + /* store DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Store(sbuffer, &(tpm_daa_session_data->DAA_joinSession)); + } + /* store daaHandle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_session_data->daaHandle); + } + return rc; +} + +/* TPM_DaaSessionData_Delete() terminates the DAA session. + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DaaSessionData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DaaSessionData_Delete(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + printf(" TPM_DaaSessionData_Delete:\n"); + if (tpm_daa_session_data != NULL) { + TPM_DAAIssuer_Delete(&(tpm_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Delete(&(tpm_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Delete(&(tpm_daa_session_data->DAA_session)); + TPM_DAAJoindata_Delete(&(tpm_daa_session_data->DAA_joinSession)); + TPM_DaaSessionData_Init(tpm_daa_session_data); + } + return; +} + +/* TPM_DaaSessionData_Copy() copies the source to the destination. The source handle is ignored, + since it might already be used. +*/ + +void TPM_DaaSessionData_Copy(TPM_DAA_SESSION_DATA *dest_daa_session_data, + TPM_HANDLE tpm_handle, + TPM_DAA_SESSION_DATA *src_daa_session_data) +{ + dest_daa_session_data->daaHandle = tpm_handle; + TPM_DAAIssuer_Copy(&(dest_daa_session_data->DAA_issuerSettings), + &(src_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Copy(&(dest_daa_session_data->DAA_tpmSpecific), + &(src_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Copy(&(dest_daa_session_data->DAA_session), + &(src_daa_session_data->DAA_session)); + TPM_DAAJoindata_Copy(&(dest_daa_session_data->DAA_joinSession), + &(src_daa_session_data->DAA_joinSession)); + dest_daa_session_data->valid= src_daa_session_data->valid; + return; +} + +/* TPM_DaaSessionData_CheckStage() verifies that the actual command processing stage is consistent + with the stage expected by the TPM state. +*/ + +TPM_RESULT TPM_DaaSessionData_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_CheckStage:\n"); + if (tpm_daa_session_data->DAA_session.DAA_stage != stage) { + printf("TPM_DaaSessionData_CheckStage: Error, stage expected %u actual %u\n", + tpm_daa_session_data->DAA_session.DAA_stage, stage); + rc = TPM_DAA_STAGE; + } + return rc; +} + +/* + TPM_DAA_ISSUER +*/ + +/* TPM_DAAIssuer_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAIssuer_Init(TPM_DAA_ISSUER *tpm_daa_issuer) +{ + printf(" TPM_DAAIssuer_Init:\n"); + + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_R0); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_R1); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_S0); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_S1); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_n); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_gamma); + memset(tpm_daa_issuer->DAA_generic_q, 0, sizeof(tpm_daa_issuer->DAA_generic_q)); + return; +} + +/* TPM_DAAIssuer_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAIssuer_Init() + After use, call TPM_DAAIssuer_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAIssuer_Load(TPM_DAA_ISSUER *tpm_daa_issuer, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAIssuer_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_ISSUER, stream, stream_size); + } + /* load DAA_digest_R0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_R0, stream, stream_size); + } + /* load DAA_digest_R1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_R1, stream, stream_size); + } + /* load DAA_digest_S0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_S0, stream, stream_size); + } + /* load DAA_digest_S1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_S1, stream, stream_size); + } + /* load DAA_digest_n */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_n, stream, stream_size); + } + /* load DAA_digest_gamma */ + if (rc == 0) { + rc = TPM_Digest_Load (tpm_daa_issuer->DAA_digest_gamma, stream, stream_size); + } + /* load DAA_generic_q */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_issuer->DAA_generic_q, sizeof(tpm_daa_issuer->DAA_generic_q), + stream, stream_size); + } + return rc; +} + +/* TPM_DAAIssuer_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAIssuer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_ISSUER *tpm_daa_issuer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAIssuer_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_ISSUER); + } + /* store DAA_digest_R0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_R0); + } + /* store DAA_digest_R1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_R1); + } + /* store DAA_digest_S0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_S0); + } + /* store DAA_digest_S1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_S1); + } + /* store DAA_digest_n */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_n); + } + /* store DAA_digest_gamma */ + if (rc == 0) { + rc = TPM_Digest_Store (sbuffer, tpm_daa_issuer->DAA_digest_gamma); + } + /* store DAA_generic_q */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_daa_issuer->DAA_generic_q, + sizeof(tpm_daa_issuer->DAA_generic_q)); + } + return rc; +} + +/* TPM_DAAIssuer_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAIssuer_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAIssuer_Delete(TPM_DAA_ISSUER *tpm_daa_issuer) +{ + printf(" TPM_DAAIssuer_Delete:\n"); + if (tpm_daa_issuer != NULL) { + TPM_DAAIssuer_Init(tpm_daa_issuer); + } + return; +} + +/* TPM_DAAIssuer_Copy() copies the source to the destination + +*/ + +void TPM_DAAIssuer_Copy(TPM_DAA_ISSUER *dest_daa_issuer, + TPM_DAA_ISSUER *src_daa_issuer) +{ + printf(" TPM_DAAIssuer_Copy:\n"); + + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_R0, src_daa_issuer->DAA_digest_R0); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_R1, src_daa_issuer->DAA_digest_R1); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_S0, src_daa_issuer->DAA_digest_S0); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_S1, src_daa_issuer->DAA_digest_S1); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_n, src_daa_issuer->DAA_digest_n); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_gamma, src_daa_issuer->DAA_digest_gamma); + memcpy(dest_daa_issuer->DAA_generic_q, src_daa_issuer->DAA_generic_q, + sizeof(src_daa_issuer->DAA_generic_q)); + return; +} + +/* + TPM_DAA_TPM +*/ + +/* TPM_DAATpm_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAATpm_Init(TPM_DAA_TPM *tpm_daa_tpm) +{ + printf(" TPM_DAATpm_Init:\n"); + TPM_Digest_Init(tpm_daa_tpm->DAA_digestIssuer); + TPM_Digest_Init(tpm_daa_tpm->DAA_digest_v0); + TPM_Digest_Init(tpm_daa_tpm->DAA_digest_v1); + TPM_Digest_Init(tpm_daa_tpm->DAA_rekey); + tpm_daa_tpm->DAA_count = 0; + return; +} + +/* TPM_DAATpm_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAATpm_Init() + After use, call TPM_DAATpm_Delete() to free memory +*/ + +TPM_RESULT TPM_DAATpm_Load(TPM_DAA_TPM *tpm_daa_tpm, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAATpm_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_TPM, stream, stream_size); + } + /* load DAA_digestIssuer */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digestIssuer, stream, stream_size); + } + /* load DAA_digest_v0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digest_v0, stream, stream_size); + } + /* load DAA_digest_v1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digest_v1, stream, stream_size); + } + /* load DAA_rekey */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_rekey, stream, stream_size); + } + /* load DAA_count */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_tpm->DAA_count), stream, stream_size); + } + return rc; +} + +/* TPM_DAATpm_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAATpm_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_TPM *tpm_daa_tpm) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAATpm_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_TPM); + } + /* store DAA_digestIssuer */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digestIssuer); + } + /* store DAA_digest_v0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digest_v0); + } + /* store DAA_digest_v1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digest_v1); + } + /* store DAA_rekey */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_rekey); + } + /* store DAA_count */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_tpm->DAA_count); + } + return rc; +} + +/* TPM_DAATpm_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAATpm_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAATpm_Delete(TPM_DAA_TPM *tpm_daa_tpm) +{ + printf(" TPM_DAATpm_Delete:\n"); + if (tpm_daa_tpm != NULL) { + TPM_DAATpm_Init(tpm_daa_tpm); + } + return; +} + +/* TPM_DAATpm_Copy() copies the source to the destination + +*/ + +void TPM_DAATpm_Copy(TPM_DAA_TPM *dest_daa_tpm, TPM_DAA_TPM *src_daa_tpm) +{ + printf(" TPM_DAATpm_Copy:\n"); + TPM_Digest_Copy(dest_daa_tpm->DAA_digestIssuer, src_daa_tpm->DAA_digestIssuer); + TPM_Digest_Copy(dest_daa_tpm->DAA_digest_v0, src_daa_tpm->DAA_digest_v0); + TPM_Digest_Copy(dest_daa_tpm->DAA_digest_v1, src_daa_tpm->DAA_digest_v1); + TPM_Digest_Copy(dest_daa_tpm->DAA_rekey, src_daa_tpm->DAA_rekey); + dest_daa_tpm->DAA_count = src_daa_tpm->DAA_count; + return; +} + +/* + TPM_DAA_CONTEXT +*/ + +/* TPM_DAAContext_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAContext_Init(TPM_DAA_CONTEXT *tpm_daa_context) +{ + printf(" TPM_DAAContext_Init:\n"); + TPM_Digest_Init(tpm_daa_context->DAA_digestContext); + TPM_Digest_Init(tpm_daa_context->DAA_digest); + TPM_Nonce_Init(tpm_daa_context->DAA_contextSeed); + memset(tpm_daa_context->DAA_scratch, 0, sizeof(tpm_daa_context->DAA_scratch)); + tpm_daa_context->DAA_stage = 0; + tpm_daa_context->DAA_scratch_null = TRUE; + return; +} + +/* TPM_DAAContext_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAContext_Init() + After use, call TPM_DAAContext_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAContext_Load(TPM_DAA_CONTEXT *tpm_daa_context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAContext_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_CONTEXT, stream, stream_size); + } + /* load DAA_digestContext */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_context->DAA_digestContext, stream, stream_size); + } + /* load DAA_digest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_context->DAA_digest, stream, stream_size); + } + /* load DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_daa_context->DAA_contextSeed, stream, stream_size); + } + /* load DAA_scratch */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_context->DAA_scratch, sizeof(tpm_daa_context->DAA_scratch), + stream, stream_size); + } + /* load DAA_stage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_daa_context->DAA_stage), stream, stream_size); + } + /* load DAA_scratch_null */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_daa_context->DAA_scratch_null), stream, stream_size); + } + return rc; +} + +/* TPM_DAAContext_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAContext_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_CONTEXT *tpm_daa_context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAContext_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_CONTEXT); + } + /* store DAA_digestContext */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_context->DAA_digestContext); + } + /* store DAA_digest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_context->DAA_digest); + } + /* store DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_daa_context->DAA_contextSeed); + } + /* store DAA_scratch */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_context->DAA_scratch, + sizeof(tpm_daa_context->DAA_scratch)); + } + /* store DAA_stage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_daa_context->DAA_stage), sizeof(BYTE)); + } + /* store DAA_scratch_null */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_daa_context->DAA_scratch_null), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_DAAContext_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAContext_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAContext_Delete(TPM_DAA_CONTEXT *tpm_daa_context) +{ + printf(" TPM_DAAContext_Delete:\n"); + if (tpm_daa_context != NULL) { + TPM_DAAContext_Init(tpm_daa_context); + } + return; +} + +/* TPM_DAAContext_Copy() copies the source to the destination + +*/ + +void TPM_DAAContext_Copy(TPM_DAA_CONTEXT *dest_daa_context, TPM_DAA_CONTEXT *src_daa_context) +{ + printf(" TPM_DAAContext_Copy:\n"); + TPM_Digest_Copy(dest_daa_context->DAA_digestContext, src_daa_context->DAA_digestContext); + TPM_Digest_Copy(dest_daa_context->DAA_digest, src_daa_context->DAA_digest); + TPM_Nonce_Copy(dest_daa_context->DAA_contextSeed, src_daa_context->DAA_contextSeed); + memcpy(dest_daa_context->DAA_scratch, src_daa_context->DAA_scratch, + sizeof(src_daa_context->DAA_scratch)); + dest_daa_context->DAA_stage = src_daa_context->DAA_stage; + dest_daa_context->DAA_scratch_null = src_daa_context->DAA_scratch_null; + return; +} + +/* + TPM_DAA_JOINDATA +*/ + +/* TPM_DAAJoindata_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAJoindata_Init(TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + printf(" TPM_DAAJoindata_Init:\n"); + memset(tpm_daa_joindata->DAA_join_u0, 0, sizeof(tpm_daa_joindata->DAA_join_u0)); + memset(tpm_daa_joindata->DAA_join_u1, 0, sizeof(tpm_daa_joindata->DAA_join_u1)); + TPM_Digest_Init(tpm_daa_joindata->DAA_digest_n0); + return; +} + +/* TPM_DAAJoindata_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAJoindata_Init() + After use, call TPM_DAAJoindata_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAJoindata_Load(TPM_DAA_JOINDATA *tpm_daa_joindata, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAJoindata_Load:\n"); + /* load DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_joindata->DAA_join_u0, + sizeof(tpm_daa_joindata->DAA_join_u0), + stream, stream_size); + } + /* load DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_joindata->DAA_join_u1, + sizeof(tpm_daa_joindata->DAA_join_u1), + stream, stream_size); + } + /* load DAA_digest_n0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_joindata->DAA_digest_n0, stream, stream_size); + } + return rc; +} + +/* TPM_DAAJoindata_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAJoindata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAJoindata_Store:\n"); + /* store DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_joindata->DAA_join_u0, + sizeof(tpm_daa_joindata->DAA_join_u0)); + } + /* store DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_joindata->DAA_join_u1, + sizeof(tpm_daa_joindata->DAA_join_u1)); + } + /* store DAA_digest_n0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_joindata->DAA_digest_n0); + } + return rc; +} + +/* TPM_DAAJoindata_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAJoindata_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAJoindata_Delete(TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + printf(" TPM_DAAJoindata_Delete:\n"); + if (tpm_daa_joindata != NULL) { + TPM_DAAJoindata_Init(tpm_daa_joindata); + } + return; +} + +/* TPM_DAAJoindata_Copy() copies the source to the destination + +*/ + +void TPM_DAAJoindata_Copy(TPM_DAA_JOINDATA *dest_daa_joindata, TPM_DAA_JOINDATA *src_daa_joindata) +{ + printf(" TPM_DAAJoindata_Copy:\n"); + memcpy(dest_daa_joindata->DAA_join_u0, src_daa_joindata->DAA_join_u0, + sizeof(src_daa_joindata->DAA_join_u0)); + memcpy(dest_daa_joindata->DAA_join_u1, src_daa_joindata->DAA_join_u1, + sizeof(src_daa_joindata->DAA_join_u1)); + TPM_Digest_Copy(dest_daa_joindata->DAA_digest_n0, src_daa_joindata->DAA_digest_n0); + return; +} + +/* + TPM_DAA_BLOB +*/ + +/* TPM_DAABlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAABlob_Init(TPM_DAA_BLOB *tpm_daa_blob) +{ + printf(" TPM_DAABlob_Init:\n"); + tpm_daa_blob->resourceType = 0; + memset(tpm_daa_blob->label, 0, sizeof(tpm_daa_blob->label)); + TPM_Digest_Init(tpm_daa_blob->blobIntegrity); + TPM_SizedBuffer_Init(&(tpm_daa_blob->additionalData)); + TPM_SizedBuffer_Init(&(tpm_daa_blob->sensitiveData)); + return; +} + +/* TPM_DAABlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAABlob_Init() + After use, call TPM_DAABlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DAABlob_Load(TPM_DAA_BLOB *tpm_daa_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAABlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_BLOB, stream, stream_size); + } + /* load resourceType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_blob->resourceType), stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_blob->label, sizeof(tpm_daa_blob->label), stream, stream_size); + } + /* load blobIntegrity */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_blob->blobIntegrity, stream, stream_size); + } + /* load additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_daa_blob->additionalData), stream, stream_size); + } + /* load sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_daa_blob->sensitiveData), stream, stream_size); + } + return rc; +} + +/* TPM_DAABlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAABlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_BLOB *tpm_daa_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAABlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_BLOB); + } + /* store resourceType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_blob->resourceType); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_blob->label, sizeof(tpm_daa_blob->label)); + } + /* store blobIntegrity */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_blob->blobIntegrity); + } + /* store additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_blob->additionalData)); + } + /* store sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_blob->sensitiveData)); + } + return rc; +} + +/* TPM_DAABlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAABlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAABlob_Delete(TPM_DAA_BLOB *tpm_daa_blob) +{ + printf(" TPM_DAABlob_Delete:\n"); + if (tpm_daa_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_daa_blob->additionalData)); + TPM_SizedBuffer_Delete(&(tpm_daa_blob->sensitiveData)); + TPM_DAABlob_Init(tpm_daa_blob); + } + return; +} + +/* + TPM_DAA_SENSITIVE +*/ + +/* TPM_DAASensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAASensitive_Init(TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + printf(" TPM_DAASensitive_Init:\n"); + TPM_SizedBuffer_Init(&(tpm_daa_sensitive->internalData)); + return; +} + +/* TPM_DAASensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAASensitive_Init() + After use, call TPM_DAASensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_DAASensitive_Load(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAASensitive_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_SENSITIVE, stream, stream_size); + } + /* load internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_daa_sensitive->internalData), stream, stream_size); + } + return rc; +} + +/* TPM_DAASensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAASensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAASensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_SENSITIVE); + } + /* store internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_sensitive->internalData)); + } + return rc; +} + +/* TPM_DAASensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAASensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAASensitive_Delete(TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + printf(" TPM_DAASensitive_Delete:\n"); + if (tpm_daa_sensitive != NULL) { + TPM_SizedBuffer_Delete(&(tpm_daa_sensitive->internalData)); + TPM_DAASensitive_Init(tpm_daa_sensitive); + } + return; +} + + +/* + Processing Common Stage Functions +*/ + +TPM_RESULT TPM_DAAJoin_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint32_t count; + TPM_HANDLE daaHandle = 0; /* no preassigned handle */ + + printf("TPM_DAAJoin_Stage00:\n"); + if (rc == 0) { + /* a. Determine that sufficient resources are available to perform a TPM_DAA_Join. */ + /* i. The TPM MUST support sufficient resources to perform one (1) + TPM_DAA_Join/TPM_DAA_Sign. The TPM MAY support additional TPM_DAA_Join/TPM_DAA_Sign + sessions. */ + /* ii. The TPM may share internal resources between the DAA operations and other variable + resource requirements: */ + /* iii. If there are insufficient resources within the stored key pool (and one or more keys + need to be removed to permit the DAA operation to execute) return TPM_NOSPACE */ + /* iv. If there are insufficient resources within the stored session pool (and one or more + authorization or transport sessions need to be removed to permit the DAA operation to + execute), return TPM_RESOURCES. */ + rc = TPM_DaaSessions_GetNewHandle(tpm_daa_session_data, + &daaHandle, /* output */ + daaHandleValid, /* output */ + tpm_state->tpm_stclear_data.daaSessions); /* array */ + } + if (rc == 0) { + /* b. Set all fields in DAA_issuerSettings = NULL */ + /* c. set all fields in DAA_tpmSpecific = NULL */ + /* d. set all fields in DAA_session = NULL */ + /* e. Set all fields in DAA_joinSession = NULL */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + /* f. Verify that sizeOf(inputData0) == sizeof(DAA_tpmSpecific -> DAA_count) and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (inputData0->size != sizeof((*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count)) { + printf("TPM_DAAJoin_Stage00: Error, inputData0 size %u should be %lu\n", + inputData0->size, + (unsigned long)sizeof((*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count)); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* g. Verify that inputData0 > 0, and return error TPM_DAA_INPUT_DATA0 on mismatch */ + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load32(&count, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage00: count %u\n", count); + if (count == 0) { + printf("TPM_DAAJoin_Stage00: Error, count is zero\n"); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* h. Set DAA_tpmSpecific -> DAA_count = inputData0 */ + (*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count = count; + /* i. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + rc = TPM_DAADigestContext_GenerateDigestJoin + ((*tpm_daa_session_data)->DAA_session.DAA_digestContext, + (*tpm_daa_session_data)); + } + if (rc == 0) { + /* j. set DAA_session -> DAA_stage = 1 */ + (*tpm_daa_session_data)->DAA_session.DAA_stage = 1; + /* k. Assign session handle for TPM_DAA_Join */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + printf("TPM_DAAJoin_Stage00: handle %08x\n", (*tpm_daa_session_data)->daaHandle); + /* l. set outputData = new session handle */ + /* i. The handle in outputData is included the output HMAC. */ + rc = TPM_SizedBuffer_Append32(outputData, (*tpm_daa_session_data)->daaHandle); + } + /* m. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_DIGEST signedDataDigest; + + printf("TPM_DAAJoin_Stage01:\n"); + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==1. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that sizeOf(inputData0) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage01: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* d. If DAA_session -> DAA_scratch == NULL: */ + if (tpm_daa_session_data->DAA_session.DAA_scratch_null) { + printf("TPM_DAAJoin_Stage01: DAA_scratch null\n"); + if (rc == 0) { + /* i. Set DAA_session -> DAA_scratch = inputData0 */ + tpm_daa_session_data->DAA_session.DAA_scratch_null = FALSE; + memcpy(tpm_daa_session_data->DAA_session.DAA_scratch, + inputData0->buffer, DAA_SIZE_issuerModulus); + /* ii. set DAA_joinSession -> DAA_digest_n0 = SHA-1(DAA_session -> DAA_scratch) */ + rc = + TPM_SHA1(tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch, + 0, NULL); + } + /* iii. set DAA_tpmSpecific -> DAA_rekey = SHA-1(tpmDAASeed || DAA_joinSession -> + DAA_digest_n0) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + TPM_NONCE_SIZE, tpm_state->tpm_permanent_data.tpmDAASeed, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + 0, NULL); + } + } + /* e. Else (If DAA_session -> DAA_scratch != NULL): */ + else { + printf("TPM_DAAJoin_Stage01: DAA_scratch not null\n"); + /* i. Set signedData = inputData0 */ + /* ii. Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage01: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* iii. Set signatureValue = inputData1 */ + /* iv. Use the RSA key == [DAA_session -> DAA_scratch] to verify that signatureValue is + a signature on signedData using TPM_SS_RSASSAPKCS1v15_SHA1 (RSA PKCS1.5 with SHA-1), + and return error TPM_DAA_ISSUER_VALIDITY on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage01: Digesting signedData\n"); + rc = TPM_SHA1(signedDataDigest, + inputData0->size, inputData0->buffer, + 0, NULL); + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage01: Verifying signature\n"); + rc = TPM_RSAVerify(inputData1->buffer, /* signature */ + inputData1->size, + TPM_SS_RSASSAPKCS1v15_INFO, /* signature scheme */ + signedDataDigest, /* signed data */ + TPM_DIGEST_SIZE, + tpm_daa_session_data->DAA_session.DAA_scratch, /* pub modulus */ + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_default_rsa_exponent, /* public exponent */ + 3); + if (rc != 0) { + printf("TPM_DAAJoin_Stage01: Error, bad signature\n"); + rc = TPM_DAA_ISSUER_VALIDITY; + } + } + /* v. Set DAA_session -> DAA_scratch = signedData */ + if (rc == 0) { + memcpy(tpm_daa_session_data->DAA_session.DAA_scratch, + inputData0->buffer, inputData1->size); + } + } + } + if (rc == 0) { + /* f. Decrement DAA_tpmSpecific -> DAA_count by 1 (unity) */ + tpm_daa_session_data->DAA_tpmSpecific.DAA_count--; + /* g. If DAA_tpmSpecific -> DAA_count ==0: */ + if (tpm_daa_session_data->DAA_tpmSpecific.DAA_count == 0) { + /* h. increment DAA_session -> DAA_Stage by 1 */ + tpm_daa_session_data->DAA_session.DAA_stage++; + } + /* i. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* j. set outputData = NULL */ + /* NOTE Done by caller */ + /* k. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage02(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + TPM_STORE_BUFFER signedDataSbuffer; + TPM_DIGEST signedDataDigest; + + printf("TPM_DAAJoin_Stage02:\n"); + outputData = outputData; /* not used */ + tpm_state = tpm_state; /* not used */ + TPM_Sbuffer_Init(&signedDataSbuffer); /* freed @1*/ + /* a. Verify that DAA_session ->DAA_stage==2. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that sizeOf(inputData0) == sizeOf(TPM_DAA_ISSUER) and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + /* NOTE cannot use sizeof because packing may not be exact */ + /* d. Set DAA_issuerSettings = inputData0. Verify that all fields in DAA_issuerSettings are + present and return error TPM_DAA_INPUT_DATA0 if not. */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_DAAIssuer_Load(&(tpm_daa_session_data->DAA_issuerSettings), &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAAJoin_Stage02: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage02: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* f. Set signatureValue = inputData1 */ + /* g. Set signedData = (DAA_joinSession -> DAA_digest_n0 || DAA_issuerSettings) */ + if (rc == 0) { + rc = TPM_Digest_Store(&signedDataSbuffer, + tpm_daa_session_data->DAA_joinSession.DAA_digest_n0); + } + if (rc == 0) { + rc = TPM_DAAIssuer_Store(&signedDataSbuffer, &(tpm_daa_session_data->DAA_issuerSettings)); + } + /* h. Use the RSA key [DAA_session -> DAA_scratch] to verify that signatureValue is a */ + /* signature on signedData using TPM_SS_RSASSAPKCS1v15_SHA1 (RSA PKCS1.5 with SHA-1), and return + error TPM_DAA_ISSUER_VALIDITY on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage02: Digesting signedData\n"); + rc = TPM_SHA1Sbuffer(signedDataDigest, &signedDataSbuffer); + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage02: Verifying signature\n"); + rc = TPM_RSAVerify(inputData1->buffer, /* signature */ + inputData1->size, + TPM_SS_RSASSAPKCS1v15_INFO, /* signature scheme */ + signedDataDigest, /* signed data */ + TPM_DIGEST_SIZE, + tpm_daa_session_data->DAA_session.DAA_scratch, /* public modulus */ + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_default_rsa_exponent, /* public exponent */ + 3); + if (rc != 0) { + printf("TPM_DAAJoin_Stage02: Error, bad signature\n"); + rc = TPM_DAA_ISSUER_VALIDITY; + } + } + /* i. Set DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store); + } + /* j. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + if (rc == 0) { + /* k. Set DAA_session -> DAA_scratch = NULL */ + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + } + /* m. return TPM_SUCCESS */ + TPM_Sbuffer_Delete(&signedDataSbuffer); /* @1*/ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage03(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf("TPM_DAAJoin_Stage03:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==3. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that sizeOf(inputData0) == sizeOf(DAA_tpmSpecific -> DAA_count) and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != sizeof(tpm_daa_session_data->DAA_tpmSpecific.DAA_count)) { + printf("TPM_DAAJoin_Stage03: Error, inputData0 size %u should be %lu\n", + inputData0->size, + (unsigned long)sizeof(tpm_daa_session_data->DAA_tpmSpecific.DAA_count)); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set DAA_tpmSpecific -> DAA_count = inputData0 */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load32(&(tpm_daa_session_data->DAA_tpmSpecific.DAA_count), &stream, &stream_size); + } + /* f. Obtain random data from the RNG and store it as DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Random(tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* g. Obtain random data from the RNG and store it as DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Random(tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* h. set outputData = NULL */ + /* NOTE Done by caller */ + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* k. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage04(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM rBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage04:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==4. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R0) == DAA_issuerSettings -> DAA_digest_R0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Checking DAA_generic_R0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_R0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set f = SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) mod + DAA_issuerSettings -> DAA_generic_q */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* k. Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 bits of f) */ + if (rc == 0) { + rc = TPM_BN_mask_bits(fBignum, DAA_power0); /* f becomes f0 */ + } + /* l. Set DAA_session -> DAA_scratch = (X^f0) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + &rBignum, /* R */ + xBignum, /* A */ + fBignum, /* P */ + nBignum); /* n */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(rBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM f1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage05:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==5. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R1) == DAA_issuerSettings -> DAA_digest_R1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Checking DAA_generic_R1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_R1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set f = SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) mod + DAA_issuerSettings -> DAA_generic_q. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* k. Shift f right by DAA_power0 bits (discard the lowest DAA_power0 bits) and label the result + f1 */ + if (rc == 0) { + rc = TPM_BN_rshift(&f1Bignum, fBignum, DAA_power0); /* f becomes f1 */ + } + /* l. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* m. Set DAA_session -> DAA_scratch = Z*(X^f1) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + f1Bignum, /* P */ + nBignum); /* N */ + } + /* n. set outputData = NULL */ + /* NOTE Done by caller */ + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(f1Bignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage06(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM zBignum = NULL; /* freed @3 */ + TPM_BIGNUM yBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage06:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==6. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S0) == DAA_issuerSettings -> DAA_digest_S0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Checking DAA_generic_S0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_S0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* k. Set Y = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating Y\n"); + rc = TPM_bin2bn(&yBignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(zBignum); /* @3 */ + TPM_BN_free(yBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage07(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + uint32_t nCount; /* DAA_count in nbo */ + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM yBignum = NULL; /* freed @3 */ + TPM_BIGNUM zBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage07:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==7. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set Y = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating Y\n"); + rc = TPM_bin2bn(&yBignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. Set DAA_session -> DAA_digest to the SHA-1 (DAA_session -> DAA_scratch || DAA_tpmSpecific + -> DAA_count || DAA_joinSession -> DAA_digest_n0) */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Computing DAA_digest\n"); + nCount = htonl(tpm_daa_session_data->DAA_tpmSpecific.DAA_count); + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(uint32_t), &nCount, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + 0, NULL); + } + /* n. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* o. set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* p. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* q. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(yBignum); /* @3 */ + TPM_BN_free(zBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage08(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *NE = NULL; /* freed @1 */ + uint32_t NELength; + TPM_DIGEST outDigest; + + printf("TPM_DAAJoin_Stage08:\n"); + /* a. Verify that DAA_session ->DAA_stage==8. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_NE and return error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_NE) { + printf("TPM_DAAJoin_Stage08: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_NE); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set NE = decrypt(inputData0, privEK) */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&NE, /* decrypted data */ + &NELength, /* length of data put into decrypt_data */ + inputData0->buffer, /* encrypted data */ + inputData0->size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* f. set outputData = SHA-1(DAA_session -> DAA_digest || NE) */ + if (rc == 0) { + rc = TPM_SHA1(outDigest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + NELength, NE, + 0, NULL); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, TPM_DIGEST_SIZE, outDigest); + } + /* g. set DAA_session -> DAA_digest = NULL */ + if (rc == 0) { + TPM_Digest_Init(tpm_daa_session_data->DAA_session.DAA_digest); + } + /* h. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* i. return TPM_SUCCESS */ + free(NE); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM rBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage09_Sign_Stage2:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==9. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific ||DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R0) == DAA_issuerSettings -> DAA_digest_R0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Checking DAA_generic_R0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain random data from the RNG and store it as DAA_session -> DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_daa_session_data->DAA_session.DAA_contextSeed); + } + /* i. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them Y. "r0" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r0); + } + /* j. Set X = DAA_generic_R0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* k. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* l. Set DAA_session -> DAA_scratch = (X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + &rBignum, /* R */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* n */ + + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(rBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y= NULL; /* freed @1 */ + TPM_BIGNUM xBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM zBignum = NULL; /* freed @4 */ + TPM_BIGNUM yBignum = NULL; /* freed @5*/ + + printf("TPM_DAAJoin_Stage10_Sign_Stage3:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==10. Return TPM_DAA_STAGE and flush handle on mismatch + h */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R1) == DAA_issuerSettings -> DAA_digest_R1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Checking DAA_generic_R1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them Y. "r1" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r1); + } + /* i. Set X = DAA_generic_R1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(xBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(zBignum); /* @4 */ + TPM_BN_free(yBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y= NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage11_Sign_Stage4:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==11. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S0) == DAA_issuerSettings -> DAA_digest_S0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Checking DAA_generic_S0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them Y. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r2); + } + /* i. Set X = DAA_generic_S0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage12:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==12. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings ) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r3 bytes using the MGF1 function and label them Y. "r3" || DAA_session -> + DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r3, /* size of Y */ + /* length of the entire seed */ + sizeof("r3") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r3") -1, "r3", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r3); + } + /* i. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* n. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM wBignum = NULL; /* freed @1 */ + TPM_BIGNUM qBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM w1Bignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage13_Sign_Stage6:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session->DAA_stage==13. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Verify that inputSize1 == DAA_SIZE_w and return error TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_w) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Error, inputData1 size %u should be %u\n", + inputData0->size, DAA_SIZE_w); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* g. Set w = inputData1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating w\n"); + rc = TPM_bin2bn(&wBignum, inputData1->buffer, inputData1->size); + } + /* FIXME added Set q = DAA_issuerSettings -> DAA_generic_q */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating q from DAA_generic_q\n"); + rc = TPM_bin2bn(&qBignum, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + /* h. Set w1 = w^( DAA_issuerSettings -> DAA_generic_q) mod (DAA_generic_gamma) */ + /* FIXME w1 = (w^q) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &w1Bignum, /* R */ + wBignum, /* A */ + qBignum, /* P */ + nBignum); /* n */ + } + /* i. If w1 != 1 (unity), return error TPM_DAA_WRONG_W */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Testing w1\n"); + rc = TPM_BN_is_one(w1Bignum); + } + /* j. Set DAA_session -> DAA_scratch = w */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + wBignum); + } + /* k. set outputData = NULL */ + /* NOTE Done by caller */ + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. return TPM_SUCCESS. */ + TPM_BN_free(wBignum); /* @1 */ + TPM_BN_free(qBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(w1Bignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM fBignum = NULL; /* freed @1 */ + TPM_BIGNUM wBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM eBignum = NULL; /* freed @4 */ + + unsigned int numBytes; /* for debug */ + + printf("TPM_DAAJoin_Stage14_Sign_Stage7:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==14. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings ) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set f = SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) mod + DAA_issuerSettings -> DAA_generic_q. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating f\n"); + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, fBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: f. f size %u\n", numBytes); + } + /* FIXME Set W = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating W\n"); + rc = TPM_bin2bn(&wBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, wBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: W size %u\n", numBytes); + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, nBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: n size %u\n", numBytes); + } + /* g. Set E = ((DAA_session -> DAA_scratch)^f) mod (DAA_generic_gamma). */ + /* FIXME E = (w^f) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &eBignum, /* R */ + wBignum, /* A */ + fBignum, /* P */ + nBignum); /* n */ + } + /* h. Set outputData = E */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Output E\n"); + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + eBignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS. */ + TPM_BN_free(fBignum); /* @1 */ + TPM_BN_free(wBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(eBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r0 = NULL; /* freed @1 */ + unsigned char *r1 = NULL; /* freed @2 */ + TPM_BIGNUM r0Bignum = NULL; /* freed @3 */ + TPM_BIGNUM r1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM r1sBignum = NULL; /* freed @5 */ + TPM_BIGNUM rBignum = NULL; /* freed @6 */ + TPM_BIGNUM e1Bignum = NULL; /* freed @7 */ + TPM_BIGNUM qBignum = NULL; /* freed @8 */ + TPM_BIGNUM nBignum = NULL; /* freed @9 */ + TPM_BIGNUM wBignum = NULL; /* freed @10 */ + + printf("TPM_DAAJoin_Stage15_Sign_Stage8:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==15. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them r0. "r0" || DAA_session + -> DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating r0\n"); + rc = TPM_MGF1_GenerateArray(&r0, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r0Bignum, r0, DAA_SIZE_r0); + } + /* g. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them r1. "r1" || DAA_session + -> DAA_contextSeedis the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating r1\n"); + rc = TPM_MGF1_GenerateArray(&r1, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r1Bignum, r1, DAA_SIZE_r1); + } + /* FIXME Set q = DAA_generic_q */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating n from DAA_generic_q\n"); + rc = TPM_bin2bn(&qBignum, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* h. set r = r0 + 2^DAA_power0 * r1 mod (DAA_issuerSettings -> DAA_generic_q). */ + /* FIXME added parentheses + h. set r = (r0 + (2^DAA_power0 * r1)) mod (DAA_issuerSettings -> DAA_generic_q). + h. set r = (r0 + (2^DAA_power0 * r1)) mod q */ + if (rc == 0) { + rc = TPM_BN_lshift(&r1sBignum, /* result, freed @5 */ + r1Bignum, /* input */ + DAA_power0); /* n */ + } + if (rc == 0) { + rc = TPM_ComputeApBmodn(&rBignum, /* result, freed @6 */ + r0Bignum, /* A */ + r1sBignum, /* B */ + qBignum); /* n */ + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating n1 from DAA_generic_gamma\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + /* FIXME Set w = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating w from DAA_scratch\n"); + rc = TPM_bin2bn(&wBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* i. set E1 = ((DAA_session -> DAA_scratch)^r) mod (DAA_generic_gamma). */ + /* (w ^ r) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &e1Bignum, /* R */ + wBignum, /* A */ + rBignum, /* P */ + nBignum); /* n */ + } + /* j. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* k. Set outputData = E1 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + e1Bignum, 0); + } + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. return TPM_SUCCESS. */ + free(r0); /* @1 */ + free(r1); /* @2 */ + TPM_BN_free(r0Bignum); /* @3 */ + TPM_BN_free(r1Bignum); /* @4 */ + TPM_BN_free(r1sBignum); /* @5 */ + TPM_BN_free(rBignum); /* @6 */ + TPM_BN_free(e1Bignum); /* @7 */ + TPM_BN_free(qBignum); /* @8 */ + TPM_BN_free(nBignum); /* @9 */ + TPM_BN_free(wBignum); /* @10 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *nt = NULL; /* freed @1 */ + + printf("TPM_DAAJoin_Stage16_Sign_Stage9:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==16. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that inputSize0 == sizeOf(TPM_DIGEST) and return error TPM_DAA_INPUT_DATA0 on + mismatch */ + if (rc == 0) { + if (inputData0->size != TPM_DIGEST_SIZE) { + printf("TPM_DAAJoin_Stage16_Sign_Stage9: Error, inputData0 size %u should be %u\n", + inputData0->size, TPM_DIGEST_SIZE); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set DAA_session -> DAA_digest = inputData0 */ + if (rc == 0) { + /* e. Set DAA_session -> DAA_digest = inputData0 */ + /* NOTE: This step is unnecessary, since the value is overridden in g. */ + /* f. Obtain DAA_SIZE_NT bytes from the RNG and label them NT */ + rc = TPM_Malloc(&nt, DAA_SIZE_NT); + } + if (rc == 0) { + rc = TPM_Random(nt, DAA_SIZE_NT); + } + /* g. Set DAA_session -> DAA_digest to the SHA-1 ( DAA_session -> DAA_digest || NT ) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + inputData0->size, inputData0->buffer, /* e. DAA_session -> DAA_digest */ + DAA_SIZE_NT, nt, + 0, NULL); + } + /* h. Set outputData = NT */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, DAA_SIZE_NT, nt); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS. */ + free(nt); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r0 = NULL; /* freed @1 */ + TPM_BIGNUM r0Bignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM s0Bignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage17_Sign_Stage11:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==17. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them r0. "r0" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage17_Sign_Stage11: Creating r0\n"); + rc = TPM_MGF1_GenerateArray(&r0, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r0Bignum, r0, DAA_SIZE_r0); + } + /* e. Set f = SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) mod + DAA_issuerSettings -> DAA_generic_q. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* f. Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 bits of f) */ + if (rc == 0) { + rc = TPM_BN_mask_bits(fBignum, DAA_power0); /* f becomes f0 */ + } + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage17_Sign_Stage11: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* g. Set s0 = r0 + (DAA_session -> DAA_digest) * f0 in Z. Compute over the integers. The + computation is not reduced with a modulus. */ + /* s0 = r0 + (c * f0) */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s0Bignum, /* result */ + r0Bignum, /* A */ + cBignum, /* B */ + fBignum); /* C */ + } + /* h. set outputData = s0 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s0Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r0); /* @1 */ + TPM_BN_free(r0Bignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(s0Bignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r1 = NULL; /* freed @1 */ + TPM_BIGNUM r1Bignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM f1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM s1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM cBignum = NULL; /* freed @6 */ + + printf("TPM_DAAJoin_Stage18_Sign_Stage12:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==18. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them r1. "r1" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage18_Sign_Stage12: Creating r1\n"); + rc = TPM_MGF1_GenerateArray(&r1, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r1Bignum, r1, DAA_SIZE_r1); + } + /* e. Set f = SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA-1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) mod + DAA_issuerSettings -> DAA_generic_q. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* f. Shift f right by DAA_power0 bits (discard the lowest DAA_power0 bits) and label the result + f1 */ + if (rc == 0) { + rc = TPM_BN_rshift(&f1Bignum, fBignum, DAA_power0); /* f becomes f1 */ + } + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage18_Sign_Stage12: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* g. Set s1 = r1 + (DAA_session -> DAA_digest)* f1 in Z. Compute over the integers. The + computation is not reduced with a modulus. */ + /* s1 = r1 + (c * f1) */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s1Bignum, /* result */ + r1Bignum, /* A */ + cBignum, /* B */ + f1Bignum); /* C */ + } + /* h. set outputData = s1 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s1Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r1); /* @1 */ + TPM_BN_free(r1Bignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(f1Bignum); /* @4 */ + TPM_BN_free(s1Bignum); /* @5 */ + TPM_BN_free(cBignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage19(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s2Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage19:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==19. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* e. Set s2 = r2 + (DAA_session -> DAA_digest)*( DAA_joinSession -> DAA_join_u0) mod + 2^DAA_power1 (Erase all but the lowest DAA_power1 bits of s2) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* s2 = (r2 + c * u0) mod_pow */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s2Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + u0Bignum); /* C */ + } + if (rc == 0) { + rc = TPM_BN_mask_bits(s2Bignum, DAA_power1); + } + /* f. set outputData = s2 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s2Bignum, 0); + } + /* insure that outputData is DAA_power1 bits */ + if (rc == 0) { + rc = TPM_SizedBuffer_ComputeEnlarge(outputData, DAA_power1 / 8); + } + /* g. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* h. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s2Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(u0Bignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage20(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @3 */ + TPM_BIGNUM s12sBignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @6 */ + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage20:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==20. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them r2. "r2" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* e. Set s12 = r2 + (DAA_session -> DAA_digest)*( DAA_joinSession -> DAA_join_u0) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* s12 = (r2 + c * u0) mod_pow */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s12Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + u0Bignum); /* C */ + } + /* FIXME for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12Bignum); + printf("TPM_DAAJoin_Stage20: e. s12 size %u\n", numBytes); + } + /* f. Shift s12 right by DAA_power1 bit (discard the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&s12sBignum, s12Bignum, DAA_power1); /* s12 becomes s12s */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12sBignum); + printf("TPM_DAAJoin_Stage20: f. s12 size %u\n", numBytes); + } + /* g. Set DAA_session -> DAA_scratch = s12 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + s12sBignum); + } + /* h. Set outputData = DAA_session -> DAA_digest */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s12Bignum); /* @3 */ + TPM_BN_free(s12sBignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + TPM_BN_free(u0Bignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage21(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r3 = NULL; /* freed @1 */ + TPM_BIGNUM r3Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s3Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM u1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @6 */ + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage21:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==21. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r3 bytes using the MGF1 function and label them r3. "r3" || DAA_session + -> DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating r3\n"); + rc = TPM_MGF1_GenerateArray(&r3, /* returned MGF1 array */ + DAA_SIZE_r3, /* size of r3 */ + /* length of the entire seed */ + sizeof("r3") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r3") -1, "r3", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r3Bignum, r3, DAA_SIZE_r3); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, r3Bignum); + printf("TPM_DAAJoin_Stage21: r3 size %u\n", numBytes); + } + /* e. Set s3 = r3 + (DAA_session -> DAA_digest)*( DAA_joinSession -> DAA_join_u1) + (DAA_session + -> DAA_scratch). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, cBignum); + printf("TPM_DAAJoin_Stage21: c size %u\n", numBytes); + } + /* FIXME Set u1 = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating u1 from DAA_joinSession -> DAA_join_u1\n"); + rc = TPM_bin2bn(&u1Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, u1Bignum); + printf("TPM_DAAJoin_Stage21: u1 size %u\n", numBytes); + } + /* FIXME Set s12 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating s12 from DAA_session -> DAA_scratch\n"); + rc = TPM_bin2bn(&s12Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12Bignum); + printf("TPM_DAAJoin_Stage21: s12 size %u\n", numBytes); + } + /* s3 = r3 + c * u1 + s12 */ + if (rc == 0) { + rc = TPM_ComputeApBxCpD(&s3Bignum, /* freed by caller */ + r3Bignum, /* A */ + cBignum, /* B */ + u1Bignum, /* C */ + s12Bignum); /* D */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s3Bignum); + printf("TPM_DAAJoin_Stage21: s3 size %u\n", numBytes); + } + /* f. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* g. set outputData = s3 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s3Bignum, 0); + } + /* h. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* i. return TPM_SUCCESS */ + free(r3); /* @1 */ + TPM_BN_free(r3Bignum); /* @2 */ + TPM_BN_free(s3Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(u1Bignum); /* @5 */ + TPM_BN_free(s12Bignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage22(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM v10Bignum = NULL; /* freed @1 */ + TPM_BIGNUM v10sBignum = NULL; /* freed @2 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @3 */ + TPM_BIGNUM u2Bignum = NULL; /* freed @4 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @5 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage22:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @6 */ + /* a. Verify that DAA_session ->DAA_stage==22. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_v0 and return error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_v0) { + printf("TPM_DAAJoin_Stage22: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_v0); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set u2 = inputData0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Creating u2\n"); + rc = TPM_bin2bn(&u2Bignum, inputData0->buffer, inputData0->size); + } + /* f. Set v0 = u2 + (DAA_joinSession -> DAA_join_u0) mod 2^DAA_power1 (Erase all but the lowest + DAA_power1 bits of v0). */ + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* FIXME factor this? */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Calculate v0\n"); + rc = TPM_BN_new(&v0Bignum); + } + /* v0 = u2 + u0 */ + if (rc == 0) { + rc = TPM_BN_add(v0Bignum, u2Bignum, u0Bignum); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, v0Bignum); + printf("TPM_DAAJoin_Stage22: f. v0 size before mask %u\n", numBytes); + } + /* v0 = v0 mod 2^DAA_power1 */ + if (rc == 0) { + rc = TPM_BN_mask_bits(v0Bignum, DAA_power1); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, v0Bignum); + printf("TPM_DAAJoin_Stage22: f. v0 size after mask %u\n", numBytes); + } + /* g. Set DAA_tpmSpecific -> DAA_digest_v0 = SHA-1(v0) */ + if (rc == 0) { + rc = TPM_SHA1_BignumGenerate(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + v0Bignum, + (DAA_power1 + 7) / 8); /* canonicalize the number of + bytes */ + } + /* h. Set v10 = u2 + (DAA_joinSession -> DAA_join_u0) in Z. Compute over the integers. + The computation is not reduced with a modulus. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Calculate v10\n"); + rc = TPM_BN_new(&v10Bignum); + } + /* v0 = u2 + u0 */ + if (rc == 0) { + rc = TPM_BN_add(v10Bignum, u2Bignum, u0Bignum); + } + /* i. Shift v10 right by DAA_power1 bits (erase the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&v10sBignum, v10Bignum, DAA_power1); + } + /* j. Set DAA_session -> DAA_scratch = v10 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + v10sBignum); + } + /* k. Set outputData */ + /* i. Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V0 and encrypt the v0 parameters using + TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to v0Bignum */ + rc = TPM_bn2binMalloc(&(tpm_daa_sensitive.internalData.buffer), + &(tpm_daa_sensitive.internalData.size), + v0Bignum, 0); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_V0); + } + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* n. return TPM_SUCCESS */ + TPM_BN_free(v10Bignum); /* @1 */ + TPM_BN_free(v10sBignum); /* @2 */ + TPM_BN_free(u0Bignum); /* @3 */ + TPM_BN_free(u2Bignum); /* @4 */ + TPM_BN_free(v0Bignum); /* @5 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage23(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM u1Bignum = NULL; /* freed @1 */ + TPM_BIGNUM u3Bignum = NULL; /* freed @2 */ + TPM_BIGNUM v1Bignum = NULL; /* freed @3 */ + TPM_BIGNUM v10Bignum = NULL; /* freed @4 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAAJoin_Stage23:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @5 */ + /* a. Verify that DAA_session ->DAA_stage==23. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_v1 and return error TPM_DAA_INPUT_DATA0 on */ + /* mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_v1) { + printf("TPM_DAAJoin_Stage23: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_v1); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set u3 = inputData0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating u3\n"); + rc = TPM_bin2bn(&u3Bignum, inputData0->buffer, inputData0->size); + } + /* f. Set v1 = u3 + DAA_joinSession -> DAA_join_u1 + DAA_session -> DAA_scratch */ + /* FIXME Set u1 = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating u1 from DAA_joinSession -> DAA_join_u1\n"); + rc = TPM_bin2bn(&u1Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* FIXME Set v10 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating v10\n"); + rc = TPM_bin2bn(&v10Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_new(&v1Bignum); + } + /* f. Set v1 = u3 + u1 + v10 */ + if (rc == 0) { + rc = TPM_BN_add(v1Bignum, u3Bignum, u1Bignum); + } + if (rc == 0) { + rc = TPM_BN_add(v1Bignum, v1Bignum,v10Bignum); + } + /* g. Set DAA_tpmSpecific -> DAA_digest_v1 = SHA-1(v1) */ + if (rc == 0) { + rc = TPM_SHA1_BignumGenerate(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v1, + v1Bignum, + DAA_SIZE_v1); /* canonicalize the number of bytes */ + } + /* h. Set outputData */ + /* i. Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V1 and encrypt the v1 parameters using + TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to v1Bignum */ + rc = TPM_bn2binMalloc(&(tpm_daa_sensitive.internalData.buffer), + &(tpm_daa_sensitive.internalData.size), + v1Bignum, 0); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_V1); + } + + + /* i. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* j. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* k. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* l. return TPM_SUCCESS */ + TPM_BN_free(u1Bignum); /* @1 */ + TPM_BN_free(u3Bignum); /* @2 */ + TPM_BN_free(v1Bignum); /* @3 */ + TPM_BN_free(v10Bignum); /* @4 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage24(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAAJoin_Stage24:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @1 */ + /* a. Verify that DAA_session ->DAA_stage==24. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. set outputData = enc(DAA_tpmSpecific) using TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage24 Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to DAA_tpmSpecific */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_daa_sensitive.internalData), + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_TPM); + } + /* e. return TPM_SUCCESS */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @2 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* returns entry in + array */ + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + TPM_HANDLE daaHandle = 0; /* no preassigned handle */ + + printf("TPM_DAASign_Stage00:\n"); + /* a. Determine that sufficient resources are available to perform a TPM_DAA_Sign. */ + /* i. The TPM MUST support sufficient resources to perform one (1) + TPM_DAA_Join/TPM_DAA_Sign. The TPM MAY support addition TPM_DAA_Join/ TPM_DAA_Sign + sessions. */ + /* ii. The TPM may share internal resources between the DAA operations and other variable + resource requirements: */ + /* iii. If there are insufficient resources within the stored key pool (and one or more keys + need to be removed to permit the DAA operation to execute) return TPM_NOSPACE */ + /* iv. If there are insufficient resources within the stored session pool (and one or more + authorization or transport sessions need to be removed to permit the DAA operation to + execute), return TPM_RESOURCES. */ + if (rc == 0) { + rc = TPM_DaaSessions_GetNewHandle(tpm_daa_session_data, /* returns entry in array */ + &daaHandle, /* output */ + daaHandleValid, /* output */ + tpm_state->tpm_stclear_data.daaSessions); /* array */ + } + /* b. Set DAA_issuerSettings = inputData0 */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_DAAIssuer_Load(&((*tpm_daa_session_data)->DAA_issuerSettings), + &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* c. Verify that all fields in DAA_issuerSettings are present and return error + TPM_DAA_INPUT_DATA0 if not. */ + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage00: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* d. set all fields in DAA_session = NULL */ + /* e. Assign new handle for session */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + printf("TPM_DAASign_Stage00: handle %08x\n", (*tpm_daa_session_data)->daaHandle); + /* f. Set outputData to new handle */ + /* i. The handle in outputData is included the output HMAC. */ + rc = TPM_SizedBuffer_Append32(outputData, (*tpm_daa_session_data)->daaHandle); + } + /* g. set DAA_session -> DAA_stage = 1 */ + /* NOTE Done by common code */ + /* h. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_DAA_SENSITIVE tpm_daa_sensitive; + unsigned char *stream; + uint32_t stream_size; + + printf("TPM_DAASign_Stage01:\n"); + outputData = outputData; /* not used */ + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @1 */ + /* a. Verify that DAA_session ->DAA_stage==1. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Set DAA_tpmSpecific = unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_TPM); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + stream = tpm_daa_sensitive.internalData.buffer; + stream_size = tpm_daa_sensitive.internalData.size; + rc = TPM_DAATpm_Load(&(tpm_daa_session_data->DAA_tpmSpecific), &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* c. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + + /* d. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific) */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_daa_session_data->DAA_session.DAA_digestContext, + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store); + } + /* e set outputData = NULL */ + /* NOTE Done by caller */ + /* f. set DAA_session -> DAA_stage =2 */ + /* NOTE Done by common code */ + /* g. return TPM_SUCCESS */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAASign_Stage05:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==5. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r4 bytes using the MGF1 function and label them Y. "r4" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r4, /* size of Y */ + /* length of the entire seed */ + sizeof("r4") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r4") -1, "r4", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r4); + } + /* i. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAASign_Stage05 Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* n. set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage10(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint8_t selector; + TPM_BOOL parentPCRStatus; + TPM_KEY_HANDLE keyHandle; + TPM_KEY *identityKey = NULL; /* the key specified by keyHandle */ + + printf("TPM_DAASign_Stage10:\n"); + /* a. Verify that DAA_session ->DAA_stage==10. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that inputSize0 == sizeOf(BYTE), and return error TPM_DAA_INPUT_DATA0 on + mismatch */ + /* e. Set selector = inputData0, verify that selector == 0 or 1, and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load8(&selector, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage10: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + printf("TPM_DAASign_Stage10: selector %u\n", selector); + switch (selector) { + case 1: + /* f. If selector == 1, verify that inputSize1 == sizeOf(TPM_DIGEST), and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != TPM_DIGEST_SIZE) { + printf("TPM_DAASign_Stage10: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* g. Set DAA_session -> DAA_digest to SHA-1 (DAA_session -> DAA_digest || 1 || + inputData1) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + 1, &selector , + inputData1->size, inputData1->buffer, + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + break; + case 0: + /* h. If selector == 0, verify that inputData1 is a handle to a TPM identity key (AIK), + and return error TPM_DAA_INPUT_DATA1 on mismatch */ + /* get the key handle */ + if (rc == 0) { + stream = inputData1->buffer; + stream_size = inputData1->size; + rc = TPM_Load32(&keyHandle, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* validate inputData1 */ + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage10: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* get the key */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetKey(&identityKey, &parentPCRStatus, + tpm_state, keyHandle, + TRUE, /* read only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* validate that it's an AIK */ + if (rc == 0) { + if (identityKey->keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_DAASign_Stage10: Error, " + "key keyUsage %04hx must be TPM_KEY_IDENTITY\n", identityKey->keyUsage); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* i. Set DAA_session -> DAA_digest to SHA-1 (DAA_session -> DAA_digest || 0 || n2) + where n2 is the modulus of the AIK */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + 1, &selector, + identityKey->pubKey.size, identityKey->pubKey.buffer, + 0, NULL); + } + break; + default: + printf("TPM_DAASign_Stage10: Error, bad selector %u\n", selector); + rc = TPM_DAA_INPUT_DATA0; + break; + } + } + /* j. Set outputData = DAA_session -> DAA_digest */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest); + } + /* k. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* l. return TPM_SUCCESS. */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage13(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s2Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @5 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage13:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @6 */ + /* a. Verify that DAA_session ->DAA_stage==13. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v0= unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: unwrapping to v0\n"); + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V0); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific -> DAA_digest_v0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: Checking v0\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + &(tpm_daa_sensitive.internalData), + (DAA_power1 + 7) / 8); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r2 bytes from the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage13 Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* g. Set s2 = r2 + (DAA_session -> DAA_digest)*( DAA_private_v0) mod 2^DAA_power1 */ + /* (erase all but the lowest DAA_power1 bits of s2) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v0 = DAA_private_v0 */ + if (rc == 0) { + rc = TPM_bin2bn(&v0Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* s2 = r2 + c * v0 mod 2^DAA_power1 */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s2Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + v0Bignum); /* C */ + } + if (rc == 0) { + rc = TPM_BN_mask_bits(s2Bignum, DAA_power1); + } + /* h. set outputData = s2 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s2Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s2Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(v0Bignum); /* @5 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage14(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @3 */ + TPM_BIGNUM s12sBignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @6 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage14:\n"); + outputData = outputData; /* not used */ + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @7 */ + /* a. Verify that DAA_session ->DAA_stage==14. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v0= unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V0); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific -> DAA_digest_v0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Checking v0\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + &(tpm_daa_sensitive.internalData), + (DAA_power1 + 7) / 8); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r2 bytes from the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* g. Set s12 = r2 + (DAA_session -> DAA_digest)*(DAA_private_v0). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v0 = DAA_private_v0 */ + if (rc == 0) { + rc = TPM_bin2bn(&v0Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* s12 = r2 + c * v0 */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s12Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + v0Bignum); /* C */ + } + /* h. Shift s12 right by DAA_power1 bits (erase the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&s12sBignum, s12Bignum, DAA_power1); /* f becomes f1 */ + } + /* i. Set DAA_session -> DAA_scratch = s12 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + s12sBignum); + } + /* j. set outputData = NULL */ + /* NOTE Done by caller */ + /* k. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* l. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s12Bignum); /* @3 */ + TPM_BN_free(s12sBignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + TPM_BN_free(v0Bignum); /* @6 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @7 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage15(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r4 = NULL; /* freed @1 */ + TPM_BIGNUM r4Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s3Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM v1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @6 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage15:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @7 */ + /* a. Verify that DAA_session ->DAA_stage==15. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v1 = unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V1); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v1) == DAA_tpmSpecific -> DAA_digest_v1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Checking v1\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v1, + &(tpm_daa_sensitive.internalData), + DAA_SIZE_v1); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r4 bytes from the MGF1 function and label them r4. "r4" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating r4\n"); + rc = TPM_MGF1_GenerateArray(&r4, /* returned MGF1 array */ + DAA_SIZE_r4, /* size of Y */ + /* length of the entire seed */ + sizeof("r4") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r4") -1, "r4", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r4Bignum, r4, DAA_SIZE_r4); + } + /* g. Set s3 = r4 + (DAA_session -> DAA_digest)*(DAA_private_v1) + (DAA_session -> + DAA_scratch). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v1 = DAA_private_v1 */ + if (rc == 0) { + rc = TPM_bin2bn(&v1Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* FIXME Set s12 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating s12 from DAA_session -> DAA_scratch\n"); + rc = TPM_bin2bn(&s12Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* s3 = r4 + c * v1 + s12 */ + if (rc == 0) { + rc = TPM_ComputeApBxCpD(&s3Bignum, /* freed by caller */ + r4Bignum, /* A */ + cBignum, /* B */ + v1Bignum, /* C */ + s12Bignum); /* D */ + } + /* h. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* i. set outputData = s3 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s3Bignum, 0); + } + /* j. Terminate the DAA session and all resources associated with the DAA sign session + handle. */ + /* NOTE Done by caller */ + /* k. return TPM_SUCCESS */ + free(r4); /* @1 */ + TPM_BN_free(r4Bignum); /* @2 */ + TPM_BN_free(s3Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(v1Bignum); /* @5 */ + TPM_BN_free(s12Bignum); /* @6 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @7 */ + return rc; +} + +/* + Stage Common Code +*/ + +/* TPM_DAADigestContext_GenerateDigestJoin() sets tpm_digest to SHA-1(DAA_tpmSpecific || + DAA_joinSession)) +*/ + +TPM_RESULT TPM_DAADigestContext_GenerateDigestJoin(TPM_DIGEST tpm_digest, + TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORED_DATA serialization */ + + printf(" TPM_DAADigestContext_GenerateDigestJoin:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Store(&sbuffer, &(tpm_daa_session_data->DAA_tpmSpecific)); + } + /* serialize DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Store(&sbuffer, &(tpm_daa_session_data->DAA_joinSession)); + } + /* calculate and return the digest */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_DAADigestContext_CheckDigestJoin() verifies that DAA_session -> DAA_digestContext == + SHA-1(DAA_tpmSpecific || DAA_joinSession). + + Returns TPM_DAA_TPM_SETTINGS on mismatch +*/ + +TPM_RESULT TPM_DAADigestContext_CheckDigestJoin(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + TPM_DIGEST tpm_digest; /* actual digest */ + + printf(" TPM_DAADigestContext_CheckDigestJoin:\n"); + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin(tpm_digest, tpm_daa_session_data); + } + if (rc == 0) { + rc = TPM_Digest_Compare(tpm_digest, tpm_daa_session_data->DAA_session.DAA_digestContext); + if (rc != 0) { + rc = TPM_DAA_TPM_SETTINGS; + } + } + return rc; +} + +/* TPM_ComputeF() computes the value F common to stages 4.j., 5.j., 14.f., 17.e., 18.e. + + j. Set f = SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) || + SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) + mod DAA_issuerSettings -> DAA_generic_q +*/ + +TPM_RESULT TPM_ComputeF(TPM_BIGNUM *fBignum, /* freed by caller */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + BYTE nZero = 0; + BYTE nOne = 1; + uint32_t nCount; /* DAA_count in nbo */ + TPM_DIGEST digest0; /* first SHA1 calculation */ + TPM_DIGEST digest1; /* second SHA1 calculation */ + TPM_BIGNUM dividend; /* digest0 || digest1 as a BIGNUM */ + TPM_BIGNUM modulus; /* DAA_generic_q as a BIGNUM */ + + printf(" TPM_ComputeF:\n"); + modulus = NULL; /* freed @1 */ + dividend = NULL; /* freed @2 */ + if (rc == 0) { + rc = TPM_BN_new(fBignum); + } + /* SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) */ + if (rc == 0) { + printf(" TPM_ComputeF: Calculate digest0\n"); + nCount = htonl(tpm_daa_session_data->DAA_tpmSpecific.DAA_count); + rc = TPM_SHA1(digest0, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + sizeof(uint32_t), &nCount, + sizeof(BYTE), &nZero, + 0, NULL); + } + /* SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) */ + if (rc == 0) { + printf(" TPM_ComputeF: Calculate digest1\n"); + rc = TPM_SHA1(digest1, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + sizeof(uint32_t), &nCount, + sizeof(BYTE), &nOne, + 0, NULL); + } + /* Construct digest0 || digest1 as a positive BIGNUM */ + if (rc == 0) { + rc = TPM_2bin2bn(÷nd, + digest0, TPM_DIGEST_SIZE, + digest1, TPM_DIGEST_SIZE); + } + /* DAA_generic_q as a positive BIGNUM */ + if (rc == 0) { + rc = TPM_bin2bn(&modulus, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* digest mod DAA_generic_q */ + if (rc == 0) { + rc = TPM_BN_mod(*fBignum, dividend, modulus); + } + TPM_BN_free(modulus); /* @1 */ + TPM_BN_free(dividend); /* @2 */ + return rc; +} + +/* TPM_ComputeAexpPmodn() performs R = (A ^ P) mod n. + + rBignum is new'ed by this function and must be freed by the caller + + If DAA_scratch is not NULL, r is returned in DAA_scratch. +*/ + +TPM_RESULT TPM_ComputeAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeAexpPmodn:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); + } + if (rc == 0) { + rc = TPM_BN_mod_exp(*rBignum, aBignum, pBignum, nBignum); + } + /* if the result should be returned in DAA_scratch */ + if ((rc == 0) && (DAA_scratch != NULL)) { + /* store the result in DAA_scratch */ + rc = TPM_ComputeDAAScratch(DAA_scratch, DAA_scratch_size, *rBignum); + } + return rc; +} + +/* TPM_ComputeZxAexpPmodn() performs DAA_scratch = Z * (A ^ P) mod n. + +*/ + +TPM_RESULT TPM_ComputeZxAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM zBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM rBignum = NULL; /* freed @1 */ + + printf(" TPM_ComputeZxAexpPmodn:\n"); + if (rc == 0) { + printf(" TPM_ComputeZxAexpPmodn: Calculate R = A ^ P mod n\n"); + rc = TPM_ComputeAexpPmodn(NULL, /* DAA_scratch */ + 0, + &rBignum, /* R */ + aBignum, /* A */ + pBignum, + nBignum); + } + if (rc == 0) { + printf(" TPM_ComputeZxAexpPmodn: Calculate R = Z * R mod n\n"); + rc = TPM_BN_mod_mul(rBignum, zBignum, rBignum, nBignum); + } + /* store the result in DAA_scratch */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(DAA_scratch, DAA_scratch_size, rBignum); + } + TPM_BN_free(rBignum); /* @1 */ + return rc; +} + +/* TPM_ComputeApBmodn() performs R = A + B mod n + +*/ + +TPM_RESULT TPM_ComputeApBmodn(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeApBmodn:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_BN_mod_add(*rBignum, aBignum, bBignum, nBignum); + } + return rc; +} + +/* TPM_ComputeApBxC() performs R = A + B * C + +*/ + +TPM_RESULT TPM_ComputeApBxC(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeApBxC:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); /* freed by caller */ + } + /* R = B * C */ + if (rc == 0) { + rc = TPM_BN_mul(*rBignum, bBignum, cBignum); + } + /* R = R + A */ + if (rc == 0) { + rc = TPM_BN_add(*rBignum, *rBignum, aBignum); + } + return rc; +} + +/* TPM_ComputeApBxCpD() performs R = A + B * C + D + +*/ + +TPM_RESULT TPM_ComputeApBxCpD(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum, + TPM_BIGNUM dBignum) +{ + TPM_RESULT rc = 0; + printf(" TPM_ComputeApBxCpD:\n"); + /* R = A + B * C */ + if (rc == 0) { + rc = TPM_ComputeApBxC(rBignum, /* freed by caller */ + aBignum, + bBignum, + cBignum); + } + /* R = R + D */ + if (rc == 0) { + rc = TPM_BN_add(*rBignum, *rBignum, dBignum); + } + return rc; +} + +/* TPM_ComputeDAAScratch() stores 'bn' in DAA_scratch + +*/ + +TPM_RESULT TPM_ComputeDAAScratch(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM bn) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeDAAScratch:\n"); + if (rc == 0) { + rc = TPM_bn2binArray(DAA_scratch, DAA_scratch_size, bn); + } + return rc; +} + +/* TPM_ComputeEnlarge() creates a buffer of size 'outSize' + + It copies 'outSize - inSize' zero bytes and then appends 'in' + + 'out' must be freed by the caller +*/ + +TPM_RESULT TPM_ComputeEnlarge(unsigned char **out, /* freed by caller */ + uint32_t outSize, + unsigned char *in, + uint32_t inSize) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (outSize <= inSize) { + printf("TPM_ComputeEnlarge: Error (fatal), inSize %u outSize %u\n", inSize, outSize); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc(out, outSize); + } + if (rc == 0) { + memset(*out, 0, outSize - inSize); /* zero left bytes */ + memcpy(*out + outSize - inSize, in, inSize); /* copy right bytes */ + } + return rc; +} + +/* TPM_SizedBuffer_ComputeEnlarge() forces 'tpm_sized_buffer' to be 'size' bytes in length. + + If generally useful, this function should be moved to tpm_sizedbuffer.c +*/ + +TPM_RESULT TPM_SizedBuffer_ComputeEnlarge(TPM_SIZED_BUFFER *tpm_sized_buffer, uint32_t size) +{ + TPM_RESULT rc = 0; + unsigned char *newPtr; /* new buffer, enlarged */ + + newPtr = NULL; /* freed by caller */ + /* if tpm_sized_buffer needs to be enlarged */ + if (tpm_sized_buffer->size != size) { + if (rc == 0) { + /* copy the TPM_SIZED_BUFFER data. enlarged, to newPtr */ + rc = TPM_ComputeEnlarge(&newPtr, size, /* output buffer */ + tpm_sized_buffer->buffer, + tpm_sized_buffer->size); + } + if (rc == 0) { + /* after the copy, the old buffer is no longer needed */ + free(tpm_sized_buffer->buffer); + /* assign the with the enlarged buffer to the TPM_SIZED_BUFFER */ + tpm_sized_buffer->buffer = newPtr; + /* update size */ + tpm_sized_buffer->size = size; + } + } + return rc; +} + +/* TPM_ComputeEncrypt() does join steps common to encrypting output data. + + It serializes the TPM_DAA_SENSITIVE, encrypts it to TPM_DAA_BLOB ->sensitiveData, adds the + resourceType, generates the TPM_DAA_BLOB -> blobIntegrity HMAC using daaProof, and serializes the + result to outputData. +*/ + +TPM_RESULT TPM_ComputeEncrypt(TPM_SIZED_BUFFER *outputData, + tpm_state_t *tpm_state, + TPM_DAA_SENSITIVE *tpm_daa_sensitive, + TPM_RESOURCE_TYPE resourceType) +{ + TPM_RESULT rc = 0; + TPM_DAA_BLOB tpm_daa_blob; + TPM_STORE_BUFFER daaSensitiveSbuffer; + + printf(" TPM_ComputeEncrypt:\n"); + TPM_DAABlob_Init(&tpm_daa_blob); /* freed @1 */ + TPM_Sbuffer_Init(&daaSensitiveSbuffer); /* freed @2 */ + + /* serialize the TPM_DAA_SENSITIVE */ + if (rc == 0) { + rc = TPM_DAASensitive_Store(&daaSensitiveSbuffer, tpm_daa_sensitive); + } + /* Create a TPM_DAA_BLOB structure */ + if (rc == 0) { + printf(" TPM_ComputeEncrypt: Create TPM_DAA_BLOB\n"); + tpm_daa_blob.resourceType = resourceType; + /* Set TPM_DAA_BLOB -> sensitiveData to the encryption of serialized TPM_DAA_SENSITIVE */ + rc = TPM_SymmetricKeyData_EncryptSbuffer + (&(tpm_daa_blob.sensitiveData), /* output buffer */ + &daaSensitiveSbuffer, /* input buffer */ + tpm_state->tpm_permanent_data.daaBlobKey); /* key */ + } + /* set TPM_DAA_BLOB -> blobIntegrity to the HMAC of TPM_DAA_BLOB using daaProof as the secret */ + if (rc == 0) { + rc = TPM_HMAC_GenerateStructure(tpm_daa_blob.blobIntegrity, /* HMAC */ + tpm_state->tpm_permanent_data.daaProof, /* HMAC key */ + &tpm_daa_blob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DAABlob_Store); /* store + function */ + } + /* ii. set outputData to the encrypted TPM_DAA_BLOB */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(outputData, &tpm_daa_blob, + (TPM_STORE_FUNCTION_T )TPM_DAABlob_Store); + } + TPM_DAABlob_Delete(&tpm_daa_blob); /* @1 */ + TPM_Sbuffer_Delete(&daaSensitiveSbuffer); /* @2 */ + return rc; +} + +/* TPM_ComputeDecrypt() does sign steps common to decrypting input data + + It deserializes 'inputData" to a TPM_DAA_BLOB, and validates the resourceType and blobIntegrity + HMAC using daaProof. It decrypts TPM_DAA_BLOB ->sensitiveData and deserializes it to a + TPM_DAA_SENSITIVE. + + tpm_daa_sensitive must be deleted by the caller +*/ + +TPM_RESULT TPM_ComputeDecrypt(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *inputData, + TPM_RESOURCE_TYPE resourceType) + +{ + TPM_RESULT rc = 0; + TPM_DAA_BLOB tpm_daa_blob; + unsigned char *stream; + uint32_t stream_size; + unsigned char *sensitiveStream; + uint32_t sensitiveStreamSize; + + printf(" TPM_ComputeDecrypt:\n"); + TPM_DAABlob_Init(&tpm_daa_blob); /* freed @1 */ + sensitiveStream = NULL; /* freed @2 */ + /* deserialize inputData to a TPM_DAA_BLOB */ + if (rc == 0) { + stream = inputData->buffer; + stream_size = inputData->size; + rc = TPM_DAABlob_Load(&tpm_daa_blob, &stream, &stream_size); + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_ComputeDecrypt: Error, bad blob input size %u\n", inputData->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* check blobIntegrity */ + if (rc == 0) { + rc = TPM_HMAC_CheckStructure(tpm_state->tpm_permanent_data.daaProof, /* HMAC key */ + &tpm_daa_blob, /* structure */ + tpm_daa_blob.blobIntegrity, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DAABlob_Store, /* store function */ + TPM_DAA_INPUT_DATA0); /* error code */ + } + /* check resourceType */ + if (rc == 0) { + if (tpm_daa_blob.resourceType != resourceType) { + printf("TPM_ComputeDecrypt: Error, resourceType %08x\n", tpm_daa_blob.resourceType); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* decrypt the TPM_DAA_BLOB -> sensitiveData */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt + (&sensitiveStream, /* output, caller frees */ + &sensitiveStreamSize, /* output */ + tpm_daa_blob.sensitiveData.buffer, /* input */ + tpm_daa_blob.sensitiveData.size, /* input */ + tpm_state->tpm_permanent_data.daaBlobKey); /* dec key */ + } + if (rc == 0) { + stream = sensitiveStream; + stream_size = sensitiveStreamSize; + rc = TPM_DAASensitive_Load(tpm_daa_sensitive, &stream, &stream_size); + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_ComputeDecrypt: Error, bad sensitive input size %u\n", sensitiveStreamSize); + rc = TPM_DAA_INPUT_DATA0; + } + } + TPM_DAABlob_Delete(&tpm_daa_blob); /* @1 */ + free(sensitiveStream); /* @2 */ + return rc; +} + +/* TPM_SHA1_BignumGenerate() converts the BIGNUM 'bn' to an array, enlarges the array to 'size', and + computes the SHA-1 hash + +*/ + +TPM_RESULT TPM_SHA1_BignumGenerate(TPM_DIGEST tpm_digest, + TPM_BIGNUM bn, + uint32_t size) +{ + TPM_RESULT rc = 0; + unsigned char *bin = NULL; /* freed @1 */ + unsigned int bytes; + unsigned char *newBin = NULL; /* freed @2, new buffer, enlarged */ + + if (rc == 0) { + rc = TPM_bn2binMalloc(&bin, &bytes, bn, 0); /* freed @1 */ + } + if (rc == 0) { + printf(" TPM_SHA1_BignumGenerate: enlarge to %u bytes, is %u bytes\n", size, bytes); + if (bytes != size) { + /* canonicalize the array size */ + if (rc == 0) { + rc = TPM_ComputeEnlarge(&newBin, size, /* output buffer */ + bin, bytes ); /* inout buffer */ + } + if (rc == 0) { + rc = TPM_SHA1(tpm_digest, + size, newBin, + 0, NULL); + } + } + else { + /* already canonicalized */ + rc = TPM_SHA1(tpm_digest, + bytes, bin, + 0, NULL); + } + } + free(bin); /* @1 */ + free(newBin); /* @2 */ + return rc; +} + +/* TPM_SHA1_SizedBufferCheck() enlarges the TPM_SIZED_BUFFER to 'size', computes the SHA-1 hash, + and validates the digest against 'tpm_digest' + + As a side effect, the TPM_SIZED_BUFFER may be enlarged. +*/ + +TPM_RESULT TPM_SHA1_SizedBufferCheck(TPM_DIGEST tpm_digest, + TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + printf(" TPM_SHA1_SizedBufferCheck: enlarge to %u bytes, is %u bytes\n", + size, tpm_sized_buffer->size); + if (tpm_sized_buffer->size != size) { + /* canonicalize the array size */ + rc = TPM_SizedBuffer_ComputeEnlarge(tpm_sized_buffer, size); + } + } + if (rc == 0) { + rc = TPM_SHA1_Check(tpm_digest, + tpm_sized_buffer->size, tpm_sized_buffer->buffer, + 0, NULL); + } + return rc; +} + +/* + Processing functions +*/ + +/* 26.1 TPM_DAA_Join rev 99 + + TPM_DAA_Join is the process that establishes the DAA parameters in the TPM for a specific DAA + issuing authority. + + outputSize and outputData are always included in the outParamDigest. This includes stage + 0, where the outputData contains the DAA session handle. +*/ + +TPM_RESULT TPM_Process_DAAJoin(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_HANDLE daaHandle; /* Session handle */ + BYTE stage = 0; /* Processing stage of join */ + TPM_SIZED_BUFFER inputData0; /* Data to be used by this capability */ + TPM_SIZED_BUFFER inputData1; /* Data to be used by this capability */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Continue use flag, TRUE if handle is still + active */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing */ + 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_BOOL daaHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* DAA session for handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outputData; /* Data produced by this capability */ + + printf("TPM_Process_DAAJoin: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData0); /* freed @1 */ + TPM_SizedBuffer_Init(&inputData1); /* freed @2 */ + TPM_SizedBuffer_Init(&outputData); /* freed @3 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&daaHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get stage */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAAJoin: daaHandle %08x\n", daaHandle); + returnCode = TPM_Load8(&stage, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAAJoin: stage %u\n", stage); + /* For stages after stage 0, daaHandle is an input. Mark it valid so it can be terminated + on error. */ + if (stage > 0) { + daaHandleValid = TRUE; + } + /* get inputData0 */ + returnCode = TPM_SizedBuffer_Load(&inputData0, &command, ¶mSize); + } + /* get inputData1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData1, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DAAJoin: 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. Use ownerAuth to verify that the Owner authorized all TPM_DAA_Join input parameters. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + Common to most or all stages + */ + /* Validate the DAA session handle after stage 0, stage 0 assigns the handle */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = + TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + tpm_state->tpm_stclear_data.daaSessions, /* array */ + daaHandle); + } + } + /* Verify that the input state is consistent with the current TPM state */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = TPM_DaaSessionData_CheckStage(tpm_daa_session_data, stage); + } + } + /* Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) and + return error TPM_DAA_TPM_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 1) { + returnCode = TPM_DAADigestContext_CheckDigestJoin(tpm_daa_session_data); + } + } + /* Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return error + TPM_DAA_ISSUER_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 3) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store, + TPM_DAA_ISSUER_SETTINGS); + } + } + /* Stages */ + if (returnCode == TPM_SUCCESS) { + switch (stage) { + case 0 : + returnCode = TPM_DAAJoin_Stage00(tpm_state, + &tpm_daa_session_data, /* entry in array */ + &daaHandleValid, + &outputData, &inputData0); + if (daaHandleValid) { + /* For stage 0, daaHandle may be generated. Extract it from the DAA session and + mark it valid, so the session can be terminated on error. */ + daaHandle = tpm_daa_session_data->daaHandle; + } + break; + case 1 : + returnCode = TPM_DAAJoin_Stage01(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 2 : + returnCode = TPM_DAAJoin_Stage02(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 3 : + returnCode = TPM_DAAJoin_Stage03(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 4 : + returnCode = TPM_DAAJoin_Stage04(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 5 : + returnCode = TPM_DAAJoin_Stage05(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 6 : + returnCode = TPM_DAAJoin_Stage06(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 7 : + returnCode = TPM_DAAJoin_Stage07(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 8 : + returnCode = TPM_DAAJoin_Stage08(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 9 : + returnCode = TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 10 : + returnCode = TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 11 : + returnCode = TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 12 : + returnCode = TPM_DAAJoin_Stage12(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 13 : + returnCode = TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 14 : + returnCode = TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 15 : + returnCode = TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 16 : + returnCode = TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 17 : + returnCode = TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 18 : + returnCode = TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 19 : + returnCode = TPM_DAAJoin_Stage19(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 20 : + returnCode = TPM_DAAJoin_Stage20(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 21 : + returnCode = TPM_DAAJoin_Stage21(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 22 : + returnCode = TPM_DAAJoin_Stage22(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 23 : + returnCode = TPM_DAAJoin_Stage23(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 24 : + returnCode = TPM_DAAJoin_Stage24(tpm_state, + tpm_daa_session_data, + &outputData); + break; + default : + printf("TPM_Process_DAAJoin: Error, Illegal stage\n"); + returnCode = TPM_DAA_STAGE; + } + } + /* + Common to most or all stages + */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + tpm_daa_session_data->DAA_session.DAA_stage++; + } + } + /* 24.e.Terminate the DAA session and all resources associated with the DAA join session + handle. */ + if (returnCode == TPM_SUCCESS) { + if (stage == 24) { + printf("TPM_Process_DAAJoin: Stage 24, terminating DAA session %08x\n", + tpm_daa_session_data->daaHandle); + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + } + /* 2. Any error return results in the TPM invalidating all resources associated with the + join */ + /* NOTE Done after response processing */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DAAJoin: 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 outputData */ + returnCode = TPM_SizedBuffer_Store(response, &outputData); + /* 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) { + /* no outParam's, set authorization response data */ + 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, 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); + } + /* on error, terminate the DAA session */ + if (((rcf != 0) || (returnCode != TPM_SUCCESS)) && daaHandleValid) { + TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + daaHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData0); /* @1 */ + TPM_SizedBuffer_Delete(&inputData1); /* @2 */ + TPM_SizedBuffer_Delete(&outputData); /* @3 */ + return rcf; +} + +/* 26.2 TPM_DAA_Sign rev 99 + + TPM protected capability; user must provide authorizations from the TPM Owner. + + outputSize and outputData are always included in the outParamDigest. This includes stage + 0, where the outputData contains the DAA session handle. +*/ + +TPM_RESULT TPM_Process_DAASign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_HANDLE daaHandle; /* Handle to the sign session */ + BYTE stage = 0; /* Stage of the sign process */ + TPM_SIZED_BUFFER inputData0; /* Data to be used by this capability */ + TPM_SIZED_BUFFER inputData1; /* Data to be used by this capability */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Continue use flag, TRUE if handle is still + active */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing */ + 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_BOOL daaHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* DAA session for handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outputData; /* Data produced by this capability */ + + printf("TPM_Process_DAASign: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData0); /* freed @1 */ + TPM_SizedBuffer_Init(&inputData1); /* freed @2 */ + TPM_SizedBuffer_Init(&outputData); /* freed @3 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&daaHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get stage */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAASign: daaHandle %08x\n", daaHandle); + returnCode = TPM_Load8(&stage, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAASign: stage %u\n", stage); + /* For stages after stage 0, daaHandle is an input. Mark it valid so it can be terminated + on error. */ + if (stage > 0) { + daaHandleValid = TRUE; + } + /* get inputData0 */ + returnCode = TPM_SizedBuffer_Load(&inputData0, &command, ¶mSize); + } + /* get inputData1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData1, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DAASign: 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. Use ownerAuth to verify that the Owner authorized all TPM_DAA_Sign input parameters. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + Common to most or all stages + */ + /* Validate the DAA session handle after stage 0, stage 0 assigns the handle */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = + TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + tpm_state->tpm_stclear_data.daaSessions, /* array */ + daaHandle); + } + } + /* Verify that the input state is consistent with the current TPM state */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = TPM_DaaSessionData_CheckStage(tpm_daa_session_data, stage); + } + } + /* Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_session.DAA_digestContext, + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store, + TPM_DAA_TPM_SETTINGS); + } + } + /* Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return error + TPM_DAA_ISSUER_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store, + TPM_DAA_ISSUER_SETTINGS); + } + } + /* Stages */ + if (returnCode == TPM_SUCCESS) { + switch (stage) { + case 0 : + returnCode = TPM_DAASign_Stage00(tpm_state, + &tpm_daa_session_data, /* returns entry in array */ + &daaHandleValid, + &outputData, + &inputData0); + if (daaHandleValid) { + /* For stage 0, daaHandle may be generated. Extract it from the DAA session and + mark it valid, so the session can be terminated on error. */ + daaHandle = tpm_daa_session_data->daaHandle; + } + break; + case 1 : + returnCode = TPM_DAASign_Stage01(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 2 : + returnCode = TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 3 : + returnCode = TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 4 : + returnCode = TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 5 : + returnCode = TPM_DAASign_Stage05(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 6 : + returnCode = TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 7 : + returnCode = TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 8 : + returnCode = TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 9 : + returnCode = TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 10 : + returnCode = TPM_DAASign_Stage10(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 11 : + returnCode = TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 12 : + returnCode = TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 13 : + returnCode = TPM_DAASign_Stage13(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 14 : + returnCode = TPM_DAASign_Stage14(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 15 : + returnCode = TPM_DAASign_Stage15(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + default : + printf("TPM_Process_DAASign: Error, Illegal stage\n"); + returnCode = TPM_DAA_STAGE; + } + } + /* + Common to most or all stages + */ + if (returnCode == TPM_SUCCESS) { + tpm_daa_session_data->DAA_session.DAA_stage++; + } + /* 15.j. Terminate the DAA session and all resources associated with the DAA sign session + handle. */ + if (returnCode == TPM_SUCCESS) { + if (stage == 15) { + printf("TPM_Process_DAASign: Stage 15, terminating DAA session %08x\n", + tpm_daa_session_data->daaHandle); + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + } + /* 2. Any error return results in the TPM invalidating all resources associated with the + join */ + /* NOTE Done after response processing */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DAASign: 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 outputData */ + returnCode = TPM_SizedBuffer_Store(response, &outputData); + /* 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) { + /* no outParam's, set authorization response data */ + 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, 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); + } + /* on error, terminate the DAA session */ + if (((rcf != 0) || (returnCode != TPM_SUCCESS)) && daaHandleValid) { + TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + daaHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData0); /* @1 */ + TPM_SizedBuffer_Delete(&inputData1); /* @2 */ + TPM_SizedBuffer_Delete(&outputData); /* @3 */ + return rcf; +} diff --git a/src/tpm12/tpm_daa.h b/src/tpm12/tpm_daa.h new file mode 100644 index 0000000..ae37a34 --- /dev/null +++ b/src/tpm12/tpm_daa.h @@ -0,0 +1,405 @@ +/********************************************************************************/ +/* */ +/* DAA Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_daa.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_DAA_H +#define TPM_DAA_H + +#include "tpm_global.h" +#include "tpm_store.h" + +/* + TPM_DAA_SESSION_DATA (the entire array) +*/ + + +void TPM_DaaSessions_Init(TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_Load(TPM_DAA_SESSION_DATA *daaSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DaaSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions); +void TPM_DaaSessions_Delete(TPM_DAA_SESSION_DATA *daaSessions); + +void TPM_DaaSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_DAA_SESSION_DATA *daaSessions); +void TPM_DaaSessions_GetSpace(uint32_t *space, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_GetNewHandle(TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_HANDLE *daaHandle, + TPM_BOOL *daaHandleValid, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_GetEntry(TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle); +TPM_RESULT TPM_DaaSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_DAA_SESSION_DATA *daaSessions, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DaaSessions_TerminateHandle(TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle); + + +/* + TPM_DAA_SESSION_DATA (one element of the array) +*/ + +void TPM_DaaSessionData_Init(TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DaaSessionData_Load(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DaaSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SESSION_DATA *tpm_daa_session_data); +void TPM_DaaSessionData_Delete(TPM_DAA_SESSION_DATA *tpm_daa_session_data); + +void TPM_DaaSessionData_Copy(TPM_DAA_SESSION_DATA *dest_daa_session_data, + TPM_HANDLE tpm_handle, + TPM_DAA_SESSION_DATA *src_daa_session_data); +TPM_RESULT TPM_DaaSessionData_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage); + +/* + TPM_DAA_ISSUER +*/ + +void TPM_DAAIssuer_Init(TPM_DAA_ISSUER *tpm_daa_issuer); +TPM_RESULT TPM_DAAIssuer_Load(TPM_DAA_ISSUER *tpm_daa_issuer, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAIssuer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_ISSUER *tpm_daa_issuer); +void TPM_DAAIssuer_Delete(TPM_DAA_ISSUER *tpm_daa_issuer); + +void TPM_DAAIssuer_Copy(TPM_DAA_ISSUER *dest_daa_issuer, + TPM_DAA_ISSUER *src_daa_issuer); + +/* + TPM_DAA_TPM +*/ + +void TPM_DAATpm_Init(TPM_DAA_TPM *tpm_daa_tpm); +TPM_RESULT TPM_DAATpm_Load(TPM_DAA_TPM *tpm_daa_tpm, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAATpm_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_TPM *tpm_daa_tpm); +void TPM_DAATpm_Delete(TPM_DAA_TPM *tpm_daa_tpm); + +void TPM_DAATpm_Copy(TPM_DAA_TPM *dest_daa_tpm, TPM_DAA_TPM *src_daa_tpm); + +/* + TPM_DAA_CONTEXT +*/ + +void TPM_DAAContext_Init(TPM_DAA_CONTEXT *tpm_daa_context); +TPM_RESULT TPM_DAAContext_Load(TPM_DAA_CONTEXT *tpm_daa_context, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAContext_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_CONTEXT *tpm_daa_context); +void TPM_DAAContext_Delete(TPM_DAA_CONTEXT *tpm_daa_context); + +void TPM_DAAContext_Copy(TPM_DAA_CONTEXT *dest_daa_context, TPM_DAA_CONTEXT *src_daa_context); + +/* + TPM_DAA_JOINDATA +*/ + +void TPM_DAAJoindata_Init(TPM_DAA_JOINDATA *tpm_daa_joindata); +TPM_RESULT TPM_DAAJoindata_Load(TPM_DAA_JOINDATA *tpm_daa_joindata, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAJoindata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_JOINDATA *tpm_daa_joindata); +void TPM_DAAJoindata_Delete(TPM_DAA_JOINDATA *tpm_daa_joindata); + +void TPM_DAAJoindata_Copy(TPM_DAA_JOINDATA *dest_daa_joindata, + TPM_DAA_JOINDATA *src_daa_joindata); + +/* + TPM_DAA_BLOB +*/ + +void TPM_DAABlob_Init(TPM_DAA_BLOB *tpm_daa_blob); +TPM_RESULT TPM_DAABlob_Load(TPM_DAA_BLOB *tpm_daa_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAABlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_BLOB *tpm_daa_blob); +void TPM_DAABlob_Delete(TPM_DAA_BLOB *tpm_daa_blob); + +/* + TPM_DAA_SENSITIVE +*/ + +void TPM_DAASensitive_Init(TPM_DAA_SENSITIVE *tpm_daa_sensitive); +TPM_RESULT TPM_DAASensitive_Load(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAASensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SENSITIVE *tpm_daa_sensitive); +void TPM_DAASensitive_Delete(TPM_DAA_SENSITIVE *tpm_daa_sensitive); + +/* + Stage Common Code +*/ + +TPM_RESULT TPM_DAADigestContext_GenerateDigestJoin(TPM_DIGEST tpm_digest, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DAADigestContext_CheckDigestJoin(TPM_DAA_SESSION_DATA *tpm_daa_session_data); + +TPM_RESULT TPM_DAASession_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage); +TPM_RESULT TPM_ComputeF(TPM_BIGNUM *fBignum, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_ComputeAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM *rBignum, + TPM_BIGNUM xBignum, + TPM_BIGNUM fBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeZxAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM zBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeApBmodn(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeApBxC(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum); +TPM_RESULT TPM_ComputeApBxCpD(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum, + TPM_BIGNUM dBignum); +TPM_RESULT TPM_ComputeDAAScratch(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM bn); +TPM_RESULT TPM_ComputeEnlarge(unsigned char **out, + uint32_t outSize, + unsigned char *in, + uint32_t inSize); +TPM_RESULT TPM_SizedBuffer_ComputeEnlarge(TPM_SIZED_BUFFER *tpm_sized_buffer, uint32_t size); +TPM_RESULT TPM_ComputeEncrypt(TPM_SIZED_BUFFER *outputData, + tpm_state_t *tpm_state, + TPM_DAA_SENSITIVE *tpm_daa_sensitive, + TPM_RESOURCE_TYPE resourceType); +TPM_RESULT TPM_ComputeDecrypt(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *inputData, + TPM_RESOURCE_TYPE resourceType); + +TPM_RESULT TPM_SHA1_BignumGenerate(TPM_DIGEST tpm_digest, + TPM_BIGNUM bn, + uint32_t size); +TPM_RESULT TPM_SHA1_SizedBufferCheck(TPM_DIGEST tpm_digest, + TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size); + +/* + Processing Common Functions +*/ + +TPM_RESULT TPM_DAAJoin_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage02(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage03(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage04(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage06(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage07(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage08(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage19(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage20(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage21(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage22(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage23(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage24(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); + +TPM_RESULT TPM_DAASign_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAASign_Stage10(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAASign_Stage13(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage14(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage15(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_DAAJoin(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 TPM_Process_DAASign(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); + +#endif diff --git a/src/tpm12/tpm_delegate.c b/src/tpm12/tpm_delegate.c new file mode 100644 index 0000000..37ebc02 --- /dev/null +++ b/src/tpm12/tpm_delegate.c @@ -0,0 +1,3944 @@ +/********************************************************************************/ +/* */ +/* Delegate Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_delegate.c 4580 2011-06-10 17:55:41Z 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 <stdlib.h> + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" + +#include "tpm_delegate.h" + +/* + TPM_DELEGATE_PUBLIC +*/ + +/* TPM_DelegatePublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegatePublic_Init(TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + printf(" TPM_DelegatePublic_Init:\n"); + tpm_delegate_public->rowLabel = 0; + TPM_PCRInfoShort_Init(&(tpm_delegate_public->pcrInfo)); + TPM_Delegations_Init(&(tpm_delegate_public->permissions)); + tpm_delegate_public->familyID = 0; + tpm_delegate_public->verificationCount = 0; + return; +} + +/* TPM_DelegatePublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DelegatePublic_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegatePublic_Load(TPM_DELEGATE_PUBLIC *tpm_delegate_public, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_PUBLIC, stream, stream_size); + } + /* load rowLabel */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_delegate_public->rowLabel), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_delegate_public->pcrInfo), stream, stream_size, FALSE); + } + /* load permissions */ + if (rc == 0) { + rc = TPM_Delegations_Load(&(tpm_delegate_public->permissions), stream, stream_size); + } + /* load the familyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegate_public->familyID), stream, stream_size); + } + /* load the verificationCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegate_public->verificationCount), stream, stream_size); + } + return rc; +} + +/* TPM_DelegatePublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegatePublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_PUBLIC); + } + /* store rowLabel */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_public->rowLabel), + sizeof(TPM_DELEGATE_LABEL)); + } + /* store pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_delegate_public->pcrInfo), FALSE); + } + /* store permissions */ + if (rc == 0) { + rc = TPM_Delegations_Store(sbuffer, &(tpm_delegate_public->permissions)); + } + /* store familyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->familyID); + } + /* store verificationCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->verificationCount); + } + return rc; +} + +/* TPM_DelegatePublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegatePublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegatePublic_Delete(TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + printf(" TPM_DeleteDelegatePublic:\n"); + if (tpm_delegate_public != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_delegate_public->pcrInfo)); + TPM_Delegations_Delete(&(tpm_delegate_public->permissions)); + TPM_DelegatePublic_Init(tpm_delegate_public); + } + return; +} + +/* TPM_DelegatePublic_Copy() copies the 'src' to the 'dest' structure + +*/ + +TPM_RESULT TPM_DelegatePublic_Copy(TPM_DELEGATE_PUBLIC *dest, + TPM_DELEGATE_PUBLIC *src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Copy:\n"); + if (rc == 0) { + /* copy rowLabel */ + dest->rowLabel = src->rowLabel; + /* copy pcrInfo */ + rc = TPM_PCRInfoShort_Copy(&(dest->pcrInfo), &(src->pcrInfo)); + } + if (rc == 0) { + /* copy permissions */ + TPM_Delegations_Copy(&(dest->permissions), &(src->permissions)); + /* copy familyID */ + dest->familyID = src->familyID; + /* copy verificationCount */ + dest->verificationCount = src->verificationCount; + } + return rc; +} + +/* + TPM_DELEGATE_SENSITIVE +*/ + +/* TPM_DelegateSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateSensitive_Init(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + printf(" TPM_DelegateSensitive_Init:\n"); + TPM_Secret_Init(tpm_delegate_sensitive->authValue); + return; +} + +/* TPM_DelegateSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DelegateSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateSensitive_Load(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateSensitive_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_SENSITIVE, stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_delegate_sensitive->authValue, stream, stream_size); + } + return rc; +} + +/* TPM_DelegateSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateSensitive_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_SENSITIVE); + } + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_delegate_sensitive->authValue); + } + return rc; +} + +/* TPM_DelegateSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateSensitive_Delete(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + printf(" TPM_DeleteDelegateSensitive:\n"); + if (tpm_delegate_sensitive != NULL) { + TPM_DelegateSensitive_Init(tpm_delegate_sensitive); + } + return; +} + +/* TPM_DelegateSensitive_DecryptEncData() decrypts 'sensitiveArea' to a stream using 'delegateKey' + and then deserializes the stream to a TPM_DELEGATE_SENSITIVE +*/ + +TPM_RESULT TPM_DelegateSensitive_DecryptEncData(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + TPM_SIZED_BUFFER *sensitiveArea, + TPM_SYMMETRIC_KEY_TOKEN delegateKey) +{ + TPM_RESULT rc = 0; + unsigned char *s1; /* decrypted sensitive data */ + uint32_t s1_length; + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + + printf(" TPM_DelegateSensitive_DecryptEncData:\n"); + s1 = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt(&s1, /* decrypted data */ + &s1_length, /* length decrypted data */ + sensitiveArea->buffer, + sensitiveArea->size, + delegateKey); + } + if (rc == 0) { + stream = s1; + stream_size = s1_length; + rc = TPM_DelegateSensitive_Load(tpm_delegate_sensitive, &stream, &stream_size); + } + free(s1); /* @1 */ + return rc; +} + +/* + TPM_DELEGATIONS +*/ + +/* TPM_Delegations_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Delegations_Init(TPM_DELEGATIONS *tpm_delegations) +{ + printf(" TPM_Delegations_Init:\n"); + tpm_delegations->delegateType = TPM_DEL_KEY_BITS; /* any legal value */ + tpm_delegations->per1 = 0; + tpm_delegations->per2 = 0; + return; +} + +/* TPM_Delegations_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DeleteDelegations() to free memory +*/ + +TPM_RESULT TPM_Delegations_Load(TPM_DELEGATIONS *tpm_delegations, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATIONS, stream, stream_size); + } + /* load delegateType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->delegateType), stream, stream_size); + } + /* load per1 */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->per1), stream, stream_size); + } + /* load per2 */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->per2), stream, stream_size); + } + /* validate parameters */ + if (rc == 0) { + if (tpm_delegations->delegateType == TPM_DEL_OWNER_BITS) { + if (tpm_delegations->per1 & ~TPM_DELEGATE_PER1_MASK) { + printf("TPM_Delegations_Load: Error, owner per1 %08x\n", tpm_delegations->per1); + rc = TPM_BAD_PARAMETER; + } + if (tpm_delegations->per2 & ~TPM_DELEGATE_PER2_MASK) { + printf("TPM_Delegations_Load: Error, owner per2 %08x\n", tpm_delegations->per2); + rc = TPM_BAD_PARAMETER; + } + } + else if (tpm_delegations->delegateType == TPM_DEL_KEY_BITS) { + if (tpm_delegations->per1 & ~TPM_KEY_DELEGATE_PER1_MASK) { + printf("TPM_Delegations_Load: Error, key per1 %08x\n", tpm_delegations->per1); + rc = TPM_BAD_PARAMETER; + } + if (tpm_delegations->per2 & ~TPM_KEY_DELEGATE_PER2_MASK) { + printf("TPM_Delegations_Load: Error, key per2 %08x\n", tpm_delegations->per2); + rc = TPM_BAD_PARAMETER; + } + } + else { + printf("TPM_Delegations_Load: Error, delegateType %08x\n", + tpm_delegations->delegateType); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_Delegations_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Delegations_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATIONS *tpm_delegations) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATIONS); + } + /* store delegateType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->delegateType); + } + /* store per1 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per1); + } + /* store per2 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per2); + } + return rc; +} + +/* TPM_Delegations_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Delegations_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Delegations_Delete(TPM_DELEGATIONS *tpm_delegations) +{ + printf(" TPM_Delegations_Delete:\n"); + if (tpm_delegations != NULL) { + TPM_Delegations_Init(tpm_delegations); + } + return; +} + +/* TPM_Delegations_Copy() copies the source to the destination + */ + +void TPM_Delegations_Copy(TPM_DELEGATIONS *dest, + TPM_DELEGATIONS *src) +{ + dest->delegateType = src->delegateType; + dest->per1 = src->per1; + dest->per2 = src->per2; + return; +} + +/* TPM_Delegations_CheckPermissionDelegation() verifies that the new delegation bits do not grant + more permissions then currently delegated. Otherwise return error TPM_AUTHFAIL. + + An error occurs if a bit is set in newDelegations -> per and clear in currentDelegations -> per +*/ + +TPM_RESULT TPM_Delegations_CheckPermissionDelegation(TPM_DELEGATIONS *newDelegations, + TPM_DELEGATIONS *currentDelegations) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_CheckPermissionDelegation:\n"); + /* check per1 */ + if (rc == 0) { + if (newDelegations->per1 & ~currentDelegations->per1) { + printf("TPM_Delegations_CheckPermissionDelegation: Error, " + "new per1 %08x current per1 %08x\n", + newDelegations->per1, currentDelegations->per1); + rc = TPM_AUTHFAIL; + } + } + /* check per2 */ + if (rc == 0) { + if (newDelegations->per2 & ~currentDelegations->per2) { + printf("TPM_Delegations_CheckPermissionDelegation: Error, " + "new per1 %08x current per1 %08x\n", + newDelegations->per1, currentDelegations->per1); + rc = TPM_AUTHFAIL; + } + } + return rc; +} + +/* TPM_Delegations_CheckPermission() verifies that the 'ordinal' has been delegated for execution + based on the TPM_DELEGATE_PUBLIC. + + It verifies that the TPM_DELEGATIONS is appropriate for the entityType. Currently, only key or + owner authorization can be delegated. + + It verifies that the TPM_DELEGATE_PUBLIC PCR's allow the delegation. +*/ + +TPM_RESULT TPM_Delegations_CheckPermission(tpm_state_t *tpm_state, + TPM_DELEGATE_PUBLIC *delegatePublic, + TPM_ENT_TYPE entityType, /* required */ + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_CheckPermission: ordinal %08x\n", ordinal); + if (rc == 0) { + switch (entityType) { + case TPM_ET_KEYHANDLE: + rc = TPM_Delegations_CheckKeyPermission(&(delegatePublic->permissions), ordinal); + break; + case TPM_ET_OWNER: + rc = TPM_Delegations_CheckOwnerPermission(&(delegatePublic->permissions), ordinal); + break; + default: + printf("TPM_Delegations_CheckPermission: Error, " + "DSAP session does not support entity type %02x\n", + entityType); + rc = TPM_AUTHFAIL; + break; + } + } + /* check that the TPM_DELEGATE_PUBLIC PCR's allow the delegation */ + if (rc == 0) { + rc = TPM_PCRInfoShort_CheckDigest(&(delegatePublic->pcrInfo), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + return rc; +} + +/* TPM_Delegations_CheckOwnerPermission() verifies that the 'ordinal' has been delegated for + execution based on the TPM_DELEGATIONS. +*/ + +TPM_RESULT TPM_Delegations_CheckOwnerPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + uint16_t ownerPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t ownerPermissionPosition; /* owner permission bit position */ + + printf(" TPM_Delegations_CheckOwnerPermission: ordinal %08x\n", ordinal); + /* check that the TPM_DELEGATIONS structure is the correct type */ + if (rc == 0) { + if (tpm_delegations->delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_Delegations_CheckOwnerPermission: Error," + "Ordinal requires owner auth but delegateType is %08x\n", + tpm_delegations->delegateType); + rc = TPM_AUTHFAIL; + } + } + /* get the block and position in the block from the ordinals table */ + if (rc == 0) { + rc = TPM_OrdinalTable_GetOwnerPermission(&ownerPermissionBlock, + &ownerPermissionPosition, + ordinal); + } + /* check that the permission bit is set in the TPM_DELEGATIONS bit map */ + if (rc == 0) { + printf(" TPM_Delegations_CheckOwnerPermission: block %u position %u\n", + ownerPermissionBlock, ownerPermissionPosition); + switch (ownerPermissionBlock) { + case 1: /* per1 */ + if (!(tpm_delegations->per1 & (1 << ownerPermissionPosition))) { + printf("TPM_Delegations_CheckOwnerPermission: Error, per1 %08x\n", + tpm_delegations->per1); + rc = TPM_AUTHFAIL; + } + break; + case 2: /* per2 */ + if (!(tpm_delegations->per2 & (1 << ownerPermissionPosition))) { + printf("TPM_Delegations_CheckOwnerPermission: Error, per2 %08x\n", + tpm_delegations->per2); + rc = TPM_AUTHFAIL; + } + break; + default: + printf("TPM_Delegations_CheckOwnerPermission: Error, block not 1 or 2\n"); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* TPM_Delegations_CheckKeyPermission() verifies that the 'ordinal' has been delegated for + execution based on the TPM_DELEGATIONS. +*/ + +TPM_RESULT TPM_Delegations_CheckKeyPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + uint16_t keyPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t keyPermissionPosition; /* key permission bit position */ + + printf(" TPM_Delegations_CheckKeyPermission: ordinal %08x\n", ordinal); + /* check that the TPM_DELEGATIONS structure is the correct type */ + if (rc == 0) { + if (tpm_delegations->delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_Delegations_CheckKeyPermission: Error," + "Ordinal requires key auth but delegateType is %08x\n", + tpm_delegations->delegateType); + rc = TPM_AUTHFAIL; + } + } + /* get the block and position in the block from the ordinals table */ + if (rc == 0) { + rc = TPM_OrdinalTable_GetKeyPermission(&keyPermissionBlock, + &keyPermissionPosition, + ordinal); + } + /* check that the permission bit is set in the TPM_DELEGATIONS bit map */ + if (rc == 0) { + printf(" TPM_Delegations_CheckKeyPermission: block %u position %u\n", + keyPermissionBlock, keyPermissionPosition); + switch (keyPermissionBlock) { + case 1: /* per1 */ + if (!(tpm_delegations->per1 & (1 << keyPermissionPosition))) { + printf("TPM_Delegations_CheckKeyPermission: Error, per1 %08x\n", + tpm_delegations->per1); + rc = TPM_AUTHFAIL; + } + break; + case 2: /* per2 */ + if (!(tpm_delegations->per2 & (1 << keyPermissionPosition))) { + printf("TPM_Delegations_CheckKeyPermission: Error, per2 %08x\n", + tpm_delegations->per2); + rc = TPM_AUTHFAIL; + } + break; + default: + printf("TPM_Delegations_CheckKeyPermission: Error, block not 1 or 2\n"); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* + TPM_DELEGATE_OWNER_BLOB +*/ + +/* TPM_DelegateOwnerBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateOwnerBlob_Init(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + printf(" TPM_DelegateOwnerBlob_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_owner_blob->pub)); + TPM_Digest_Init(tpm_delegate_owner_blob->integrityDigest); + TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->additionalArea)); + TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->sensitiveArea)); + return; +} + +/* TPM_DelegateOwnerBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateOwnerBlob_Init() + After use, call TPM_DelegateOwnerBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateOwnerBlob_Load(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateOwnerBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_OWNER_BLOB, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_owner_blob->pub), stream, stream_size); + } + /* check that permissions are owner */ + if (rc == 0) { + if (tpm_delegate_owner_blob->pub.permissions.delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_DelegateOwnerBlob_Load: Error, delegateType expected %08x found %08x\n", + TPM_DEL_OWNER_BITS, tpm_delegate_owner_blob->pub.permissions.delegateType); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_owner_blob->integrityDigest, stream, stream_size); + } + /* load additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->additionalArea), stream, stream_size); + } + /* load sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->sensitiveArea), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateOwnerBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateOwnerBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateOwnerBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_OWNER_BLOB); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_owner_blob->pub)); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_owner_blob->integrityDigest); + } + /* store additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->additionalArea)); + } + /* store sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->sensitiveArea)); + } + return rc; +} + +/* TPM_DelegateOwnerBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateOwnerBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateOwnerBlob_Delete(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + printf(" TPM_DelegateOwnerBlob_Delete:\n"); + if (tpm_delegate_owner_blob != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_owner_blob->pub)); + TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->additionalArea)); + TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->sensitiveArea)); + TPM_DelegateOwnerBlob_Init(tpm_delegate_owner_blob); + } + return; +} + +/* + TPM_DELEGATE_KEY_BLOB +*/ + +/* TPM_DelegateKeyBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateKeyBlob_Init(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + printf(" TPM_DelegateKeyBlob_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_key_blob->pub)); + TPM_Digest_Init(tpm_delegate_key_blob->integrityDigest); + TPM_Digest_Init(tpm_delegate_key_blob->pubKeyDigest); + TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->additionalArea)); + TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->sensitiveArea)); + return; +} + +/* TPM_DelegateKeyBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateKeyBlob_Init() + After use, call TPM_DelegateKeyBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateKeyBlob_Load(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateKeyBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELG_KEY_BLOB, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_key_blob->pub), stream, stream_size); + } + /* check that permissions are key */ + if (rc == 0) { + if (tpm_delegate_key_blob->pub.permissions.delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_DelegateKeyBlob_Load: Error, delegateType expected %08x found %08x\n", + TPM_DEL_KEY_BITS, tpm_delegate_key_blob->pub.permissions.delegateType); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_key_blob->integrityDigest, stream, stream_size); + } + /* load pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_key_blob->pubKeyDigest, stream, stream_size); + } + /* load additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->additionalArea), stream, stream_size); + } + /* load sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->sensitiveArea), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateKeyBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateKeyBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateKeyBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELG_KEY_BLOB); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_key_blob->pub)); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->integrityDigest); + } + /* store pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->pubKeyDigest); + } + /* store additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->additionalArea)); + } + /* store sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->sensitiveArea)); + } + return rc; +} + +/* TPM_DelegateKeyBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateKeyBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateKeyBlob_Delete(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + printf(" TPM_DelegateKeyBlob_Delete:\n"); + if (tpm_delegate_key_blob != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_key_blob->pub)); + TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->additionalArea)); + TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->sensitiveArea)); + TPM_DelegateKeyBlob_Init(tpm_delegate_key_blob); + } + return; +} + +/* + TPM_FAMILY_TABLE +*/ + +/* TPM_FamilyTable_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_FamilyTable_Init(TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + + printf(" TPM_FamilyTable_Init: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) { + TPM_FamilyTableEntry_Init(&(tpm_family_table->famTableRow[i])); + } + return; +} + +/* TPM_FamilyTable_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_FamilyTable_Init() + After use, call TPM_FamilyTable_Delete() to free memory +*/ + +TPM_RESULT TPM_FamilyTable_Load(TPM_FAMILY_TABLE *tpm_family_table, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_Load: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_FamilyTableEntry_Load(&(tpm_family_table->famTableRow[i]), + stream, + stream_size); + } + return rc; +} + +/* TPM_FamilyTable_Store() + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_Store: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_FamilyTableEntry_Store(sbuffer, + &(tpm_family_table->famTableRow[i]), store_tag); + } + return rc; +} + +/* TPM_FamilyTable_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_FamilyTable_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_FamilyTable_Delete(TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + + printf(" TPM_FamilyTable_Delete: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + if (tpm_family_table != NULL) { + for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) { + TPM_FamilyTableEntry_Delete(&(tpm_family_table->famTableRow[i])); + } + TPM_FamilyTable_Init(tpm_family_table); + } + return; +} + +/* TPM_FamilyTable_GetEntry() searches all entries for the entry matching the familyID, and returns + the TPM_FAMILY_TABLE_ENTRY associated with the familyID. + + Returns + 0 for success + TPM_BADINDEX if the familyID is not found +*/ + +TPM_RESULT TPM_FamilyTable_GetEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */ + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_FamilyTable_GetEntry: familyID %08x\n", familyID); + for (i = 0, found = FALSE ; (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) && !found ; i++) { + if (tpm_family_table->famTableRow[i].valid && + (tpm_family_table->famTableRow[i].familyID == familyID)) { /* found */ + found = TRUE; + *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]); + } + } + if (!found) { + printf("TPM_FamilyTable_GetEntry: Error, familyID %08x not found\n", familyID); + rc = TPM_BADINDEX; + } + return rc; +} + +/* TPM_FamilyTable_GetEnabledEntry() searches all entries for the entry matching the familyID, and + returns the TPM_FAMILY_TABLE_ENTRY associated with the familyID. + + Similar to TPM_FamilyTable_GetEntry() but returns an error if the entry is disabled. + + Returns + 0 for success + TPM_BADINDEX if the familyID is not found + TPM_DISABLED_CMD if the TPM_FAMILY_TABLE_ENTRY -> TPM_FAMFLAG_ENABLED is FALSE +*/ + +TPM_RESULT TPM_FamilyTable_GetEnabledEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTable_GetEnabledEntry: familyID %08x\n", familyID); + if (rc == 0) { + rc = TPM_FamilyTable_GetEntry(tpm_family_table_entry, + tpm_family_table, + familyID); + } + if (rc == 0) { + if (!((*tpm_family_table_entry)->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_FamilyTable_GetEnabledEntry: Error, family %08x disabled\n", familyID); + rc = TPM_DISABLED_CMD; + } + } + return rc; +} + +/* TPM_FamilyTable_IsSpace() returns success if an entry is available, an error if not. + + If success, 'family_table_entry' holds the first free family table row. +*/ + +TPM_RESULT TPM_FamilyTable_IsSpace(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */ + TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + TPM_BOOL isSpace; + TPM_RESULT rc = 0; + + + printf(" TPM_FamilyTable_IsSpace:\n"); + for (i = 0, isSpace = FALSE ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN; i++) { + *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]); + if (!((*tpm_family_table_entry)->valid)) { + printf(" TPM_FamilyTable_IsSpace: Found space at %lu\n", (unsigned long)i); + isSpace = TRUE; + break; + } + } + if (!isSpace) { + printf(" TPM_FamilyTable_IsSpace: Error, no space found\n"); + rc = TPM_RESOURCES; + } + return rc; +} + +/* TPM_FamilyTable_StoreValid() stores only the valid (occupied) entries + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_StoreValid: \n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + /* store only the valid rows */ + if (tpm_family_table->famTableRow[i].valid) { + /* store only the publicly visible members */ + printf(" TPM_FamilyTable_StoreValid: Entry %lu is valid\n", (unsigned long)i); + printf(" TPM_FamilyTable_StoreValid: Entry family ID is %08x\n", + tpm_family_table->famTableRow[i].familyID); + rc = TPM_FamilyTableEntry_StorePublic(sbuffer, + &(tpm_family_table->famTableRow[i]), store_tag); + } + } + return rc; +} + +/* + TPM_FAMILY_TABLE_ENTRY +*/ + +/* TPM_FamilyTableEntry_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_FamilyTableEntry_Init(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry) +{ + printf(" TPM_FamilyTableEntry_Init:\n"); + tpm_family_table_entry->familyLabel = 0; + tpm_family_table_entry->familyID = 0; + tpm_family_table_entry->verificationCount = 0; + tpm_family_table_entry->flags = 0; + tpm_family_table_entry->valid = FALSE; + return; +} + +/* TPM_FamilyTableEntry_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_FamilyTableEntry_Init() + After use, call TPM_FamilyTableEntry_Delete() to free memory +*/ + +TPM_RESULT TPM_FamilyTableEntry_Load(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_Load:\n"); + /* load tag */ + /* the tag is not serialized when storing TPM_PERMANENT_DATA, to save NV space */ + /* load familyLabel */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_family_table_entry->familyLabel), stream, stream_size); + } + /* load familyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->familyID), stream, stream_size); + } + /* load verificationCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->verificationCount), stream, stream_size); + } + /* load flags */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->flags), stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_family_table_entry->valid), stream, stream_size); + } + if (rc == 0) { + printf(" TPM_FamilyTableEntry_Load: label %02x familyID %08x valid %u\n", + tpm_family_table_entry->familyLabel, + tpm_family_table_entry->familyID, + tpm_family_table_entry->valid); + } + return rc; +} + +/* TPM_FamilyTableEntry_Store() stores all members of the structure + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTableEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_Store:\n"); + /* store public, visible members */ + if (rc == 0) { + rc = TPM_FamilyTableEntry_StorePublic(sbuffer, tpm_family_table_entry, store_tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->valid), + sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_FamilyTableEntry_StorePublic() stores only the public, visible members of the structure + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTableEntry_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_StorePublic:\n"); + /* store tag */ + if ((rc == 0) && (store_tag)) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_FAMILY_TABLE_ENTRY); + } + /* store familyLabel */ + if (rc == 0) { + TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->familyLabel), + sizeof(TPM_FAMILY_LABEL)); + } + /* store familyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->familyID); + } + /* store verificationCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->verificationCount); + } + /* store flags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->flags); + } + return rc; +} + +/* TPM_FamilyTableEntry_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_FamilyTableEntry_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_FamilyTableEntry_Delete(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry) +{ + printf(" TPM_FamilyTableEntry_Delete:\n"); + if (tpm_family_table_entry != NULL) { + TPM_FamilyTableEntry_Init(tpm_family_table_entry); + } + return; +} + +/* + TPM_DELEGATE_TABLE +*/ + +/* TPM_DelegateTable_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateTable_Init(TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + size_t i; + + printf(" TPM_DelegateTable_Init: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) { + TPM_DelegateTableRow_Init(&(tpm_delegate_table->delRow[i])); + } + return; +} + +/* TPM_DelegateTable_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateTable_Init() + After use, call TPM_DelegateTable_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateTable_Load(TPM_DELEGATE_TABLE *tpm_delegate_table, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_DelegateTable_Load: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_DelegateTableRow_Load(&(tpm_delegate_table->delRow[i]), + stream, + stream_size); + } + return rc; +} + +/* TPM_DelegateTable_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_DelegateTable_Store: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_DelegateTableRow_Store(sbuffer, &(tpm_delegate_table->delRow[i])); + } + return rc; +} + +/* TPM_DelegateTable_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateTable_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateTable_Delete(TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + size_t i; + + printf(" TPM_DelegateTable_Delete: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + if (tpm_delegate_table != NULL) { + for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) { + TPM_DelegateTableRow_Delete(&(tpm_delegate_table->delRow[i])); + } + TPM_DelegateTable_Init(tpm_delegate_table); + } + return; +} + +/* TPM_DelegateTable_StoreValid() store only the valid (occupied) entries. Each entry is prepended + with it's index. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_DelegateTable_StoreValid:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + /* store only the valid rows */ + if (tpm_delegate_table->delRow[i].valid) { + /* a. Write the TPM_DELEGATE_INDEX to delegateTable */ + printf(" TPM_DelegateTable_StoreValid: Entry %u is valid\n", i); + printf(" TPM_DelegateTable_StoreValid: Entry family ID is %08x\n", + tpm_delegate_table->delRow[i].pub.familyID); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, i); + } + /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table->delRow[i].pub)); + } + } + } + return rc; +} + +/* TPM_DelegateTable_GetRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate table. + + The row may not have valid data. + */ + +TPM_RESULT TPM_DelegateTable_GetRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTable_GetRow: index %u\n", rowIndex); + if (rc == 0) { + if (rowIndex >= TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) { + printf("TPM_DelegateTable_GetRow: index %u out of range\n", rowIndex); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]); + } + return rc; +} + +/* TPM_DelegateTable_GetValidRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate + table. + + The row must have valid data. + */ + +TPM_RESULT TPM_DelegateTable_GetValidRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + rc = TPM_DelegateTable_GetRow(delegateTableRow, + tpm_delegate_table, + rowIndex); + } + if (rc == 0) { + *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]); + if (!(*delegateTableRow)->valid) { + printf("TPM_DelegateTable_GetValidRow: index %u invalid\n", rowIndex); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* + TPM_DELEGATE_TABLE_ROW +*/ + +/* TPM_DelegateTableRow_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateTableRow_Init(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + printf(" TPM_DelegateTableRow_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_table_row->pub)); + TPM_Secret_Init(tpm_delegate_table_row->authValue); + tpm_delegate_table_row->valid = FALSE; + return; +} + +/* TPM_DelegateTableRow_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateTableRow_Init() + After use, call TPM_DelegateTableRow_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateTableRow_Load(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTableRow_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_TABLE_ROW, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_table_row->pub), stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_delegate_table_row->authValue, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_delegate_table_row->valid), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateTableRow_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTableRow_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTableRow_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_TABLE_ROW); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table_row->pub)); + } + /* store authValue */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_delegate_table_row->authValue); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_table_row->valid), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_DelegateTableRow_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateTableRow_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateTableRow_Delete(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + printf(" TPM_DelegateTableRow_Delete:\n"); + if (tpm_delegate_table_row != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_table_row->pub)); + TPM_DelegateTableRow_Init(tpm_delegate_table_row); + } + return; +} + +/* + Processing Functions +*/ + +/* 19.1 TPM_Delegate_Manage rev 115 + + TPM_Delegate_Manage is the fundamental process for managing the Family tables, including + enabling/disabling Delegation for a selected Family. Normally TPM_Delegate_Manage must be + executed at least once (to create Family tables for a particular family) before any other type of + Delegation command in that family can succeed. + + Delegate_Manage is authorized by the TPM Owner if an Owner is installed, because changing a table + is a privileged Owner operation. If no Owner is installed, Delegate_Manage requires no privilege + to execute. This does not disenfranchise an Owner, since there is no Owner, and simplifies + loading of tables during platform manufacture or on first-boot. Burn-out of TPM non-volatile + storage by inappropriate use is mitigated by the TPM's normal limits on NV-writes in the absence + of an Owner. Tables can be locked after loading, to prevent subsequent tampering, and only + unlocked by the Owner, his delegate, or the act of removing the Owner (even if there is no + Owner). + + TPM_Delegate_Manage command is customized by opcode: + + (1) TPM_FAMILY_ENABLE enables/disables use of a family and all the rows of the delegate table + belonging to that family, + + (2) TPM_FAMILY_ADMIN can be used to prevent further management of the Tables until an Owner is + installed, or until the Owner is removed from the TPM. (Note that the Physical Presence command + TPM_ForceClear always enables further management, even if TPM_ForceClear is used when no Owner is + installed.) + + (3) TPM_FAMILY_CREATE creates a new family. + + (4) TPM_FAMILY_INVALIDATE invalidates an existing family. +*/ + +TPM_RESULT TPM_Process_DelegateManage(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_FAMILY_ID familyID; /* The familyID that is to be managed */ + TPM_FAMILY_OPERATION opCode = 0; /* Operation to be performed by this command. */ + TPM_SIZED_BUFFER opData; /* Data necessary to implement opCode */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* 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_SECRET savedAuth; /* saved copy for response */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow = NULL; /* family table row containing familyID */ + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER retData; /* Returned data */ + + printf("TPM_Process_DelegateManage: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&opData); /* freed @1 */ + TPM_Sbuffer_Init(&retData); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get familyID parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&familyID, &command, ¶mSize); + } + /* get opCode parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: familyID %08x\n", familyID); + returnCode = TPM_Load32(&opCode, &command, ¶mSize); + } + /* get opData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: opCode %u\n", opCode); + returnCode = TPM_SizedBuffer_Load(&opData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_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, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateManage: 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. If opCode != TPM_FAMILY_CREATE */ + /* a. Locate familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return + TPM_BADINDEX if not found */ + /* b. Set FR, a TPM_FAMILY_TABLE_ENTRY, to TPM_FAMILY_TABLE. famTableRow[familyRow] */ + if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE)) { + printf("TPM_Process_DelegateManage: Not creating, get entry for familyID %08x\n", + familyID); + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + /* 2. If tag = TPM_TAG_RQU_AUTH1_COMMAND */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* a. Validate the command and parameters using ownerAuth, return TPM_AUTHFAIL on error */ + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through + ownerReference delegation) */ + if ((auth_session_data->protocolID == TPM_PID_DSAP) || + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) { + /* i. If opCode = TPM_FAMILY_CREATE */ + /* (1) The TPM MUST ignore familyID */ + /* ii. Else */ + if (opCode != TPM_FAMILY_CREATE) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* (1) Verify that the familyID associated with authHandle matches the familyID + parameter, return TPM_DELEGATE_FAMILY on error */ + if (returnCode == TPM_SUCCESS) { + if (delegatePublic->familyID != familyID) { + printf("TPM_Process_DelegateManage: Error, familyID %08x should be %08x\n", + familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + } + } + } + /* 3. Else */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + /* a. If TPM_PERMANENT_DATA -> ownerAuth is valid, return TPM_AUTHFAIL */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_DelegateManage: Error, owner installed but no authorization\n"); + returnCode = TPM_AUTHFAIL ; + } + } + /* b. If opCode != TPM_FAMILY_CREATE and FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE, return + TPM_DELEGATE_LOCK */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + if ((opCode != TPM_FAMILY_CREATE) && (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK)) { + printf("TPM_Process_DelegateManage: Error, row locked\n"); + returnCode = TPM_DELEGATE_LOCK; + } + } + /* c. Validate max NV writes without an owner */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_DelegateManage: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + if (returnCode == TPM_SUCCESS){ + /* iv. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be + performed */ + nv1Incremented = TRUE; + } + } + /* 4. The TPM invalidates sessions */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: Invalidate sessions\n"); + /* a. MUST invalidate all DSAP sessions */ + /* b. MUST invalidate all OSAP sessions associated with the delegation table */ + /* d. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + /* c. MUST set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + } + /* + 5. If opCode == TPM_FAMILY_CREATE + */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_CREATE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_CREATE\n"); + /* a. Validate that sufficient space exists within the TPM to store an additional family and + map F2 to the newly allocated space. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_IsSpace(&familyRow, /* output */ + &(tpm_state->tpm_permanent_data.familyTable)); + } + /* b. Validate that opData is a TPM_FAMILY_LABEL */ + if (returnCode == TPM_SUCCESS) { + /* i. If opDataSize != sizeof(TPM_FAMILY_LABEL) return TPM_BAD_PARAM_SIZE */ + if (opData.size != sizeof(TPM_FAMILY_LABEL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* c. Map F2 to a TPM_FAMILY_TABLE_ENTRY */ + /* NOTE Done by TPM_FamilyTable_IsSpace() */ + /* i. Set F2 -> tag to TPM_TAG_FAMILY_TABLE_ENTRY */ + /* NOTE Done by TPM_FamilyTableEntry_Init() */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set F2 -> familyLabel to opData */ + familyRow->familyLabel = *(opData.buffer); + /* d. Increment TPM_PERMANENT_DATA -> lastFamilyID by 1 */ + tpm_state->tpm_permanent_data.lastFamilyID++; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after NVRAM is written */ + writeAllNV = TRUE; + /* e. Set F2 -> familyID = TPM_PERMANENT_DATA -> lastFamilyID */ + familyRow->familyID = tpm_state->tpm_permanent_data.lastFamilyID; + /* f. Set F2 -> verificationCount = 1 */ + familyRow->verificationCount = 1; + /* g. Set F2 -> flags -> TPM_FAMFLAG_ENABLED to FALSE */ + familyRow->flags &= ~TPM_FAMFLAG_ENABLED; + /* h. Set F2 -> flags -> TPM_DELEGATE_ADMIN_LOCK to FALSE */ + familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK; + /* i. Set retDataSize = 4 */ + /* j. Set retData = F2 -> familyID */ + printf("TPM_Process_DelegateManage: Created familyID %08x\n", familyRow->familyID); + familyRow->valid = TRUE; + returnCode = TPM_Sbuffer_Append32(&retData, familyRow->familyID); + } + /* k. Return TPM_SUCCESS */ + } + /* 6. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */ + if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE) && + (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { /* only if auth-1 */ + + if (auth_session_data->protocolID == TPM_PID_DSAP) { + continueAuthSession = FALSE; + } + } + /* 7. If opCode == TPM_FAMILY_ADMIN */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ADMIN)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ADMIN\n"); + /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */ + if (returnCode == TPM_SUCCESS) { + if (opData.size != sizeof(TPM_BOOL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* b. Set (FR -> flags -> TPM_DELEGATE_ADMIN_LOCK) = opData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: TPM_FAMILY_ADMIN opData %02x\n", + opData.buffer[0]); + if (*(TPM_BOOL *)(opData.buffer)) { + familyRow->flags |= TPM_DELEGATE_ADMIN_LOCK; + } + else { + familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK; + } + printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n", + familyRow->flags); + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + } + } + /* 8. else If opflag == TPM_FAMILY_ENABLE */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ENABLE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ENABLE\n"); + /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */ + if (returnCode == TPM_SUCCESS) { + if (opData.size != sizeof(TPM_BOOL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* b. Set FR -> flags-> TPM_FAMFLAG_ENABLED = opData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: TPM_FAMILY_ENABLE opData %02x\n", + opData.buffer[0]); + if (*(TPM_BOOL *)(opData.buffer)) { + familyRow->flags |= TPM_FAMFLAG_ENABLED; + } + else { + familyRow->flags &= ~TPM_FAMFLAG_ENABLED; + } + printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n", + familyRow->flags); + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + } + } + /* 9. else If opflag == TPM_FAMILY_INVALIDATE */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_INVALIDATE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_INVALIDATE\n"); + /* a. Invalidate all data associated with familyRow */ + /* i. All data is all information pointed to by FR */ + /* ii. return TPM_SELFTEST_FAILED on failure */ + TPM_FamilyTableEntry_Delete(familyRow); + /* b.The TPM MAY invalidate delegate rows that contain the same familyID. */ + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + writeAllNV = TRUE; + } + /* 10. Else return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((opCode != TPM_FAMILY_CREATE) && + (opCode != TPM_FAMILY_ADMIN) && + (opCode != TPM_FAMILY_ENABLE) && + (opCode != TPM_FAMILY_INVALIDATE)) { + printf("TPM_Process_DelegateManage: Error, bad opCode %08x\n", opCode); + returnCode = TPM_BAD_PARAMETER; + } + } + /* if writing NV and this is a no owner NV write, update the count with the previously + incremented value */ + if (returnCode == TPM_SUCCESS) { + if (writeAllNV && nv1Incremented) { + printf("TPM_Process_DelegateManage: noOwnerNVWrite %u\n", nv1); + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateManage: 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; + /* append retDataSize and retData */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &retData); + /* 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, + savedAuth, /* saved 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(&opData); /* @1 */ + TPM_Sbuffer_Delete(&retData); /* @2 */ + return rcf; +} + +/* 19.2 TPM_Delegate_CreateKeyDelegation rev 109 + + This command delegates privilege to use a key by creating a blob that can be used by TPM_DSAP. + + There is no check for appropriateness of the key's key usage against the key permission + settings. If the key usage is incorrect, this command succeeds, but the delegated command will + fail. + + These blobs CANNOT be used as input data for TPM_LoadOwnerDelegation because the internal TPM + delegate table can store owner delegations only. + + (TPM_Delegate_CreateOwnerDelegation must be used to delegate Owner privilege.) + + The use restrictions that may be present on the key pointed to by keyHandle are not enforced for + this command. Stated another way CreateKeyDelegation is not a use of the key. + + The publicInfo -> familyID can specify a disabled family row. The family row is checked when the + key delegation is used in a DSAP session, not when it is created. +*/ + +TPM_RESULT TPM_Process_DelegateCreateKeyDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key. */ + TPM_DELEGATE_PUBLIC publicInfo; /* The public information necessary to fill in the blob */ + TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption + key is the shared secret from the authorization session + protocol.*/ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use + of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL parentPCRStatus; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DIGEST a1Auth; + TPM_DELEGATE_SENSITIVE m1DelegateSensitive; + TPM_STORE_BUFFER delegateSensitive_sbuffer; + TPM_DELEGATE_KEY_BLOB p1DelegateKeyBlob; + + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation information. + */ + + printf("TPM_Process_DelegateCreateKeyDelegation: Ordinal Entry\n"); + TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */ + TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */ + TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */ + TPM_DelegateKeyBlob_Init(&p1DelegateKeyBlob); /* freed @4 */ + TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get publicInfo parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateKeyDelegation: keyHandle %08x\n", keyHandle); + returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateCreateKeyDelegation: 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. Verify AuthData for the command and parameters using privAuth */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the authorization */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + publicInfo.familyID); + } + /* 3. If the key authentication is in fact a delegation, then the TPM SHALL validate the command + and parameters using Delegation authorisation, then */ + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + printf("TPM_Process_DelegateCreateKeyDelegation: Authentication is a delegation\n"); + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return + TPM_DELEGATE_FAMILY on error */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, " + "familyID %u should be %u\n", + publicInfo.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* b. If TPM_FAMILY_TABLE.famTableRow[ authHandle -> familyID] -> flags -> + TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, family %u disabled\n", + publicInfo.familyID); + returnCode = TPM_DISABLED_CMD; + } + } + /* c. Verify that the delegation bits in publicInfo do not grant more permissions then + currently delegated. Otherwise return error TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions), + &(delegatePublic->permissions)); + } + } + /* 4. Check that publicInfo -> delegateType is TPM_DEL_KEY_BITS */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.permissions.delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, " + "delegateType %08x not a key delegation\n", + publicInfo.permissions.delegateType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on + error */ + /* NOTE Done by TPM_AuthSessions_GetData() */ + /* 6. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + delAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 7. Create h1 the SHA-1 of TPM_STORE_PUBKEY structure of the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DelegateCreateKeyDelegation: Decrypted a1", a1Auth); + returnCode = TPM_SHA1_GenerateStructure(p1DelegateKeyBlob.pubKeyDigest, + &(key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */ + /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_Init() */ + /* b. Set M1 -> authValue to a1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth); + /* c. The TPM MAY add additional information of a sensitive nature relative to the + delegation */ + /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */ + /* serialize M1 */ + returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive); + } + /* encrypt with delegate key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateKeyDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(p1DelegateKeyBlob.sensitiveArea), + &delegateSensitive_sbuffer, + tpm_state->tpm_permanent_data.delegateKey); + } + /* 10. Create P1 a TPM_DELEGATE_KEY_BLOB */ + /* a. Set P1 -> tag to TPM_TAG_DELG_KEY_BLOB */ + /* NOTE Done by TPM_DelegateKeyBlob_Init() */ + /* b. Set P1 -> pubKeyDigest to H1 */ + /* NOTE Done by TPM_StorePubkey_GenerateDigest() */ + /* c. Set P1 -> pub to PublicInfo */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegatePublic_Copy(&(p1DelegateKeyBlob.pub), &publicInfo); + } + /* d. Set P1 -> pub -> verificationCount to familyRow -> verificationCount */ + if (returnCode == TPM_SUCCESS) { + p1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount; + /* e. Set P1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_DelegateKeyBlob_Init() */ + /* f. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The + information MAY include symmetric IV, symmetric mode of encryption and other data that + allows the TPM to process the blob in the future. */ + /* g. Set P1 -> sensitiveSize to the size of M2 */ + /* h. Set P1 -> sensitiveArea to M2 */ + /* NOTE Encrypted directly into p1DelegateKeyBlob.sensitiveArea */ + /* 11. Calculate H2 the HMAC of P1 using tpmProof as the secret */ + /* 12. Set P1 -> integrityDigest to H2 */ + /* NOTE It is safe to HMAC directly into TPM_DELEGATE_KEY_BLOB, since the structure + is serialized before the HMAC is performed */ + returnCode = TPM_HMAC_GenerateStructure + (p1DelegateKeyBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &p1DelegateKeyBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */ + } + /* 13. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 14. Return P1 as blob */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Store(&blobSbuffer, &p1DelegateKeyBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateCreateKeyDelegation: 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 blobSize and blob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_DelegatePublic_Delete(&publicInfo); /* @1 */ + TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */ + TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */ + TPM_DelegateKeyBlob_Delete(&p1DelegateKeyBlob); /* @4 */ + TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */ + return rcf; +} + +/* 19.3 TPM_Delegate_CreateOwnerDelegation rev 98 + + TPM_Delegate_CreateOwnerDelegation delegates the Owner's privilege to use a set of command + ordinals, by creating a blob. Such blobs can be used as input data for TPM_DSAP or + TPM_Delegate_LoadOwnerDelegation. + + TPM_Delegate_CreateOwnerDelegation includes the ability to void all existing delegations (by + incrementing the verification count) before creating the new delegation. This ensures that the + new delegation will be the only delegation that can operate at Owner privilege in this + family. This new delegation could be used to enable a security monitor (a local separate entity, + or remote separate entity, or local host entity) to reinitialize a family and perhaps perform + external verification of delegation settings. Normally the ordinals for a delegated security + monitor would include TPM_Delegate_CreateOwnerDelegation (this command) in order to permit the + monitor to create further delegations, and TPM_Delegate_UpdateVerification to reactivate some + previously voided delegations. + + If the verification count is incremented and the new delegation does not delegate any privileges + (to any ordinals) at all, or uses an authorisation value that is then discarded, this family's + delegations are all void and delegation must be managed using actual Owner authorisation. + + (TPM_Delegate_CreateKeyDelegation must be used to delegate privilege to use a key.) +*/ + +TPM_RESULT TPM_Process_DelegateCreateOwnerDelegation(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_BOOL increment; /* Flag dictates whether verificationCount will be + incremented */ + TPM_DELEGATE_PUBLIC publicInfo; /* The public parameters for the blob */ + TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption + key is the shared secret from the OSAP protocol.*/ + TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner authentication + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC key:ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* 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_SECRET savedAuth; /* saved copy for response */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_BOOL writeAllNV = FALSE; + TPM_DIGEST a1Auth; + TPM_DELEGATE_SENSITIVE m1DelegateSensitive; + TPM_STORE_BUFFER delegateSensitive_sbuffer; /* serialization of delegateSensitive */ + TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation + information. */ + + printf("TPM_Process_DelegateCreateOwnerDelegation: Ordinal Entry\n"); + TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */ + TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */ + TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */ + TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @4 */ + TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get increment parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&increment, &command, ¶mSize); + } + /* get publicInfo parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: increment %02x\n", increment); + returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateCreateOwnerDelegation: 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 authenticate the command using TPM Owner authentication. Return TPM_AUTHFAIL + on failure. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate the + row return TPM_BADINDEX if not found */ + /* a. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + publicInfo.familyID); + } + /* 3. If the TPM Owner authentication is in fact a delegation, then the TPM SHALL validate the + command and parameters using Delegation authorisation, then */ + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return + TPM_DELEGATE_FAMILY */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, " + "familyID %u should be %u\n", + publicInfo.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* b. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, family %u disabled\n", + publicInfo.familyID); + returnCode = TPM_DISABLED_CMD; + } + } + /* c. Verify that the delegation bits in publicInfo do not grant more permissions then + currently delegated. Otherwise return error TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions), + &(delegatePublic->permissions)); + } + } + /* 4. Check that publicInfo -> delegateType is TPM_DEL_OWNER_BITS */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.permissions.delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, bad delegateType %08x\n", + publicInfo.permissions.delegateType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on + error */ + /* NOTE Done by TPM_AuthSessions_GetData() */ + /* 7. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle */ + /* NOTE 7. moved before 6. because it needs the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + delAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 6. If increment == TRUE */ + if ((returnCode == TPM_SUCCESS) && increment) { + /* a. Increment FR -> verificationCount */ + familyRow->verificationCount++; + writeAllNV = TRUE; + /* b. Set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + /* c. The TPM invalidates sessions */ + /* i. MUST invalidate all DSAP sessions */ + /* ii. MUST invalidate all OSAP sessions associated with the delegation table */ + /* iii. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_SENSITIVE\n"); + /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_Init() */ + /* b. Set M1 -> authValue to a1 */ + TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth); + /* c. Set other M1 fields as determined by the TPM vendor */ + } + /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */ + /* serialize M1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive); + } + /* encrypt with delegate key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(b1DelegateOwnerBlob.sensitiveArea), + &delegateSensitive_sbuffer, + tpm_state->tpm_permanent_data.delegateKey); + } + /* 10. Create B1 a TPM_DELEGATE_OWNER_BLOB */ + /* a. Set B1 -> tag to TPM_TAG_DELG_OWNER_BLOB */ + /* NOTE Done by TPM_DelegateOwnerBlob_Init() */ + /* b. Set B1 -> pub to publicInfo */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_OWNER_BLOB\n"); + returnCode = TPM_DelegatePublic_Copy(&(b1DelegateOwnerBlob.pub), &publicInfo); + } + /* c. Set B1 -> sensitiveSize to the size of M2 */ + /* d. Set B1 -> sensitiveArea to M2 */ + /* NOTE Encrypted directly into b1DelegateOwnerBlob */ + /* e. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_DelegateOwnerBlob_Init() */ + if (returnCode == TPM_SUCCESS) { + /* f. Set B1 pub -> verificationCount to FR -> verificationCount */ + b1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount; + /* 11. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The + information MAY include symmetric IV, symmetric mode of encryption and other data that + allows the TPM to process the blob in the future. */ + /* 12. Create H1 the HMAC of B1 using tpmProof as the secret */ + /* 13. Set B1 -> integrityDigest to H1 */ + /* NOTE It is safe to HMAC directly into TPM_DELEGATE_OWNER_BLOB, since the structure + is serialized before the HMAC is performed */ + returnCode = TPM_HMAC_GenerateStructure + (b1DelegateOwnerBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &b1DelegateOwnerBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */ + } + /* 14. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 15. Return B1 as blob */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Store(&blobSbuffer, &b1DelegateOwnerBlob); + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateCreateOwnerDelegation: 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 blobSize and blob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved 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_DelegatePublic_Delete(&publicInfo); /* @1 */ + TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */ + TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */ + TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @4 */ + TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */ + return rcf; +} + +/* 19.4 TPM_Delegate_LoadOwnerDelegation rev 109 + + This command loads a delegate table row blob into a non-volatile delegate table row. + Delegate_LoadOwnerDelegation can be used during manufacturing or on first boot (when no Owner is + installed), or after an Owner is installed. If an Owner is installed, Delegate_LoadOwnerDelegation + requires Owner authorisation, and sensitive information must be encrypted. + + Burn-out of TPM non-volatile storage by inappropriate use is mitigated by the TPM's normal limits + on NV- writes in the absence of an Owner. Tables can be locked after loading using + TPM_Delegate_Manage, to prevent subsequent tampering. + + A management system outside the TPM is expected to manage the delegate table rows stored on the + TPM, and can overwrite any previously stored data. There is no way to explicitly delete a + delegation entry. A new entry can overwrite an invalid entry. + + This command cannot be used to load key delegation blobs into the TPM +*/ + +TPM_RESULT TPM_Process_DelegateLoadOwnerDelegation(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_DELEGATE_INDEX index; /* The index of the delegate row to be written */ + uint32_t blobSize; /* The size of the delegate blob */ + TPM_DELEGATE_OWNER_BLOB d1Blob; /* Delegation information, including encrypted + portions as appropriate */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC + key:ownerAuth */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* 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_SECRET savedAuth; /* saved copy for response */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + TPM_DELEGATE_TABLE_ROW *delegateTableRow; + unsigned char *stream; + uint32_t stream_size; + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DelegateLoadOwnerDelegation: Ordinal Entry\n"); + TPM_DelegateOwnerBlob_Init(&d1Blob); /* freed @1 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get index parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&index, &command, ¶mSize); + } + /* get blobSize parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateLoadOwnerDelegation: index %u\n", index); + returnCode = TPM_Load32(&blobSize, &command, ¶mSize); + } + /* get blob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&d1Blob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_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, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateLoadOwnerDelegation: 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. Map blob to D1 a TPM_DELEGATE_OWNER_BLOB. */ + /* a. Validate that D1 -> tag == TPM_TAG_DELEGATE_OWNER_BLOB */ + /* Done by TPM_DelegateOwnerBlob_Load() */ + /* 2. Locate D1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + /* 3. Set FR to TPM_FAMILY_TABLE -> famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1Blob.pub.familyID); + } + /* 4. If TPM Owner is installed */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + /* a. Validate the command and parameters using TPM Owner authorization, return + TPM_AUTHFAIL on error */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_AUTH1_COMMAND) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "owner installed but no authorization\n"); + returnCode = TPM_AUTHFAIL; + } + } + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through + ownerReference delegation), verify that D1 -> pub -> familyID matches authHandle -> + familyID, on error return TPM_DELEGATE_FAMILY */ + if ((returnCode == TPM_SUCCESS) && + ((auth_session_data->protocolID == TPM_PID_DSAP) || + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER))) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + if (returnCode == TPM_SUCCESS) { + if (d1Blob.pub.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "familyID %u should be %u\n", + d1Blob.pub.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + } + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) { + /* a. If FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE return TPM_DELEGATE_LOCK */ + if (returnCode == TPM_SUCCESS) { + if (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, row locked\n"); + returnCode = TPM_DELEGATE_LOCK; + } + } + /* b. Validate max NV writes without an owner */ + if (returnCode == TPM_SUCCESS) { + /* i. Set NV1 to PD -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + } + /* iv. Set PD -> noOwnerNVWrite to NV1 */ + if (returnCode == TPM_SUCCESS) { + /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be + performed */ + nv1Incremented = TRUE; + } + } + /* 6. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + /* NOTE Done by TPM_FamilyTable_GetEnabledEntry() */ + /* 7. If TPM Owner is installed, validate the integrity of the blob */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Checking integrityDigest\n"); + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3, return TPM_AUTHFAIL on mismatch */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1Blob, /* structure */ + d1Blob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* 8. If TPM Owner is installed, create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 -> + sensitiveArea using TPM_DELEGATE_KEY. */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Decrypting sensitiveArea\n"); + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, /* decrypted data */ + &(d1Blob.sensitiveArea), /* encrypted */ + tpm_state->tpm_permanent_data.delegateKey); + } + } + /* 8. Otherwise set S1 = D1 -> sensitiveArea */ + if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) { + stream = d1Blob.sensitiveArea.buffer; + stream_size = d1Blob.sensitiveArea.size; + returnCode = TPM_DelegateSensitive_Load(&s1DelegateSensitive, &stream, &stream_size); + } + /* 9. Validate S1 */ + /* a. Validate that S1 -> tag == TPM_TAG_DELEGATE_SENSITIVE, return TPM_INVALID_STRUCTURE on + error */ + /* NOTE Done by TPM_DelegateSensitive_Load() */ + /* 10. Validate that index is a valid value for delegateTable, return TPM_BADINDEX on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateTable_GetRow(&delegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + index); + } + /* 11. The TPM invalidates sessions */ + if (returnCode == TPM_SUCCESS) { + /* a. MUST invalidate all DSAP sessions */ + /* b. MUST invalidate all OSAP sessions associated with the delegation table */ + /* c. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 12. Copy data to the delegate table row */ + if (returnCode == TPM_SUCCESS) { + /* a. Copy the TPM_DELEGATE_PUBLIC from D1 -> pub to TPM_DELEGATE_TABLE -> delRow[index] -> + pub. */ + returnCode = TPM_DelegatePublic_Copy(&delegateTableRow->pub, &(d1Blob.pub)); + writeAllNV = TRUE; + } + if (returnCode == TPM_SUCCESS) { + delegateTableRow->valid = TRUE; + /* b. Copy the TPM_SECRET from S1 -> authValue to TPM_DELEGATE_TABLE -> delRow[index] -> + authValue. */ + TPM_Secret_Copy(delegateTableRow->authValue, s1DelegateSensitive.authValue); + /* c. Set TPM_STCLEAR_DATA-> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + } + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + /* d. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */ + if (auth_session_data->protocolID == TPM_PID_DSAP) { + continueAuthSession = FALSE; + } + } + /* if writing NV and this is a no owner NV write, update the count with the previously + incremented value */ + if (returnCode == TPM_SUCCESS) { + if (writeAllNV && nv1Incremented) { + printf("TPM_Process_DelegateLoadOwnerDelegation: noOwnerNVWrite %u\n", nv1); + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + /* write back TPM_PERMANENT_DATA */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateLoadOwnerDelegation: 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) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved 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_DelegateOwnerBlob_Delete(&d1Blob); /* @1 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @2 */ + return rcf; +} + +/* 19.5 TPM_Delegate_ReadTable rev 87 + + This command is used to read from the TPM the public contents of the family and delegate tables + that are stored on the TPM. Such data is required during external verification of tables. + + There are no restrictions on the execution of this command; anyone can read this information + regardless of the state of the PCRs, regardless of whether they know any specific AuthData value + and regardless of whether or not the enable and admin bits are set one way or the other. +*/ + +TPM_RESULT TPM_Process_DelegateReadTable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER familySbuffer; /* Array of TPM_FAMILY_TABLE_ENTRY + elements */ + TPM_STORE_BUFFER delegateSbuffer; /* Array of TPM_DELEGATE_INDEX and + TPM_DELEGATE_PUBLIC elements */ + + printf("TPM_Process_DelegateReadTable: Ordinal Entry\n"); + TPM_Sbuffer_Init(&familySbuffer); /* freed @1 */ + TPM_Sbuffer_Init(&delegateSbuffer); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateReadTable: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Set familyTableSize to the number of valid families on the TPM times + sizeof(TPM_FAMILY_TABLE_ELEMENT). */ + /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */ + /* 2. Copy the valid entries in the internal family table to the output array familyTable */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_StoreValid(&familySbuffer, + &(tpm_state->tpm_permanent_data.familyTable), + TRUE); /* standard, store the tag */ + } + /* 3. Set delegateTableSize to the number of valid delegate table entries on the TPM times + (sizeof(TPM_DELEGATE_PUBLIC) + 4). */ + /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */ + /* 4. For each valid entry */ + /* a. Write the TPM_DELEGATE_INDEX to delegateTable */ + /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateTable_StoreValid(&delegateSbuffer, + &(tpm_state->tpm_permanent_data.delegateTable)); + } + /* 5. Return TPM_SUCCESS */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateReadTable: 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; + /* append familyTableSize and familyTable */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &familySbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* append delegateTableSize and delegateTable */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &delegateSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&familySbuffer); /* @1 */ + TPM_Sbuffer_Delete(&delegateSbuffer); /* @2 */ + return rcf; +} + +/* 19.6 TPM_Delegate_UpdateVerification rev 87 + + UpdateVerification sets the verificationCount in an entity (a blob or a delegation row) to the + current family value, in order that the delegations represented by that entity will continue to + be accepted by the TPM. +*/ + +TPM_RESULT TPM_Process_DelegateUpdateVerification(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_SIZED_BUFFER inputData; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or + TPM_DELEGATE_INDEX */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_STRUCTURE_TAG d1Tag; /* input structure tag */ + TPM_DELEGATE_INDEX d1DelegateIndex; + TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow = NULL; + TPM_FAMILY_ID familyID = 0; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER outputDataSbuffer; /* TPM_DELEGATE_KEY_BLOB or + TPM_DELEGATE_OWNER_BLOB */ + + printf("TPM_Process_DelegateUpdateVerification: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */ + TPM_Sbuffer_Init(&outputDataSbuffer); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inputData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateUpdateVerification: 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. Verify the TPM Owner, directly or indirectly through delegation, authorizes the command + and parameters, on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Determine the type of inputData (TPM_DELEGATE_TABLE_ROW or TPM_DELEGATE_OWNER_BLOB + or TPM_DELEGATE_KEY_BLOB) and map D1 to that structure */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = inputData.buffer; + stream_size = inputData.size; + /* the inputData is either a table index or a blob */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + /* if it's an index, get the index */ + returnCode = TPM_Load32(&d1DelegateIndex, &stream, &stream_size); + } + else { + /* if it's a blob, get the blob structure tag to determine the blob type */ + returnCode = TPM_Load16(&d1Tag, &stream, &stream_size); + } + } + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = inputData.buffer; + stream_size = inputData.size; + /* if inputData is a table index */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + /* a. Mapping to TPM_DELEGATE_TABLE_ROW requires taking inputData as a tableIndex and + locating the appropriate row in the table */ + returnCode = + TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + d1DelegateIndex); + familyID = d1DelegateTableRow->pub.familyID; + } + /* if inputData is a blob */ + else { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob, + &stream, &stream_size); + familyID = d1DelegateOwnerBlob.pub.familyID; + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob, + &stream, &stream_size); + familyID = d1DelegateKeyBlob.pub.familyID; + break; + default: + printf("TPM_Process_DelegateUpdateVerification: Error, invalid tag %04hx\n", d1Tag); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + } + /* 3. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB Validate the integrity of + D1 */ + if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) { + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateOwnerBlob, /* structure */ + d1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateKeyBlob, /* structure */ + d1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + break; + /* default error tested above */ + } + } + /* 4. Locate (D1 -> pub -> familyID) in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* 6. If delegated, verify that family of the delegated Owner-auth is the same as D1: + (authHandle -> familyID) == (D1 -> pub -> familyID); otherwise return error + TPM_DELEGATE_FAMILY */ + if (returnCode == TPM_SUCCESS) { + if (familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateUpdateVerification: Error, " + "familyID %u should be %u\n", + familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* 7. If delegated, verify that the family of the delegated Owner-auth is enabled: if + (authHandle -> familyID -> flags TPM_FAMFLAG_ENABLED) is FALSE, return + TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateUpdateVerification: Error, family %u disabled\n", + familyID); + returnCode = TPM_DISABLED_CMD; + } + } + } + /* 8. Set D1 -> verificationCount to FR -> verificationCount */ + if (returnCode == TPM_SUCCESS) { + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + d1DelegateTableRow->pub.verificationCount = familyRow->verificationCount; + writeAllNV = TRUE; + } + else { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + d1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount; + break; + case TPM_TAG_DELG_KEY_BLOB: + d1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount; + break; + /* default error tested above */ + } + } + } + /* 9. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB set the integrity of D1 */ + if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) { + /* a. Set D1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_GenerateStructure() */ + /* b. Create H1 the HMAC of D1 using tpmProof as the secret */ + /* c. Set D1 -> integrityDigest to H1 */ + /* NOTE It is safe to HMAC directly into the blob, since the structure is serialized before + the HMAC is performed */ + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_HMAC_GenerateStructure + (d1DelegateOwnerBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &d1DelegateOwnerBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */ + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_HMAC_GenerateStructure + (d1DelegateKeyBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &d1DelegateKeyBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */ + break; + } + } + /* If updating a delegate row, write back TPM_PERMANENT_DATA */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* 10. If D1 is a blob recreate the blob and return it */ + else { + if (returnCode == TPM_SUCCESS) { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_DelegateOwnerBlob_Store(&outputDataSbuffer, + &d1DelegateOwnerBlob); + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_DelegateKeyBlob_Store(&outputDataSbuffer, + &d1DelegateKeyBlob); + break; + /* default error tested above */ + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateUpdateVerification: 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 outputSize and outputData */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &outputDataSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */ + TPM_Sbuffer_Delete(&outputDataSbuffer); /* @4 */ + return rcf; +} + +/* 19.7 TPM_Delegate_VerifyDelegation rev 105 + + VerifyDelegation interprets a delegate blob and returns success or failure, depending on whether + the blob is currently valid. The delegate blob is NOT loaded into the TPM. +*/ + +TPM_RESULT TPM_Process_DelegateVerifyDelegation(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_SIZED_BUFFER delegation; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB */ + + /* 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 */ + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_STRUCTURE_TAG d1Tag; /* input structure tag */ + TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_FAMILY_ID familyID; + TPM_FAMILY_VERIFICATION verificationCount = 0; + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DelegateVerifyDelegation: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&delegation); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get delegation parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&delegation, &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_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateVerifyDelegation: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Determine the type of blob */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = delegation.buffer; + stream_size = delegation.size; + returnCode = TPM_Load16(&d1Tag, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = delegation.buffer; + stream_size = delegation.size; + switch (d1Tag) { + /* 1. If delegation -> tag is equal to TPM_TAG_DELEGATE_OWNER_BLOB then */ + case TPM_TAG_DELEGATE_OWNER_BLOB: + /* a. Map D1 a TPM_DELEGATE_BLOB_OWNER to delegation */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob, + &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + familyID = d1DelegateOwnerBlob.pub.familyID; + verificationCount = d1DelegateOwnerBlob.pub.verificationCount; + } + break; + /* 2. Else if delegation -> tag = TPM_TAG_DELG_KEY_BLOB */ + case TPM_TAG_DELG_KEY_BLOB: + /* a. Map D1 a TPM_DELEGATE_KEY_BLOB to delegation */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + familyID = d1DelegateKeyBlob.pub.familyID; + verificationCount = d1DelegateKeyBlob.pub.verificationCount; + } + break; + /* 3. Else return TPM_BAD_PARAMETER */ + default: + printf("TPM_Process_DelegateVerifyDelegation: Error, invalid tag %04hx\n", d1Tag); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* 4. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return + TPM_BADINDEX if not found */ + /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* 6. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + /* 7. Validate that D1 -> pub -> verificationCount matches FR -> verificationCount, on mismatch + return TPM_FAMILYCOUNT */ + if (returnCode == TPM_SUCCESS) { + if (verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DelegateVerifyDelegation: Error, " + "verificationCount mismatch %u %u\n", + verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* 8. Validate the integrity of D1 */ + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateOwnerBlob, /* structure */ + d1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + else { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateKeyBlob, /* structure */ + d1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + } + /* 9. Create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateVerifyDelegation: Decrypting sensitiveArea\n"); + if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) { + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, + &(d1DelegateOwnerBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + else { + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, + &(d1DelegateKeyBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + } + /* 10. Validate S1 values */ + /* a. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_DecryptEncData() */ + /* b. Return TPM_BAD_PARAMETER on error */ + /* 11. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateVerifyDelegation: 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&delegation); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */ + return rcf; +} diff --git a/src/tpm12/tpm_delegate.h b/src/tpm12/tpm_delegate.h new file mode 100644 index 0000000..d4f6cb6 --- /dev/null +++ b/src/tpm12/tpm_delegate.h @@ -0,0 +1,257 @@ +/********************************************************************************/ +/* */ +/* Delegate Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_delegate.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_DELEGATE_H +#define TPM_DELEGATE_H + +#include "tpm_structures.h" + +/* + TPM_DELEGATE_PUBLIC +*/ + +void TPM_DelegatePublic_Init(TPM_DELEGATE_PUBLIC *tpm_delegate_public); +TPM_RESULT TPM_DelegatePublic_Load(TPM_DELEGATE_PUBLIC *tpm_delegate_public, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegatePublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_PUBLIC *tpm_delegate_public); +void TPM_DelegatePublic_Delete(TPM_DELEGATE_PUBLIC *tpm_delegate_public); + +TPM_RESULT TPM_DelegatePublic_Copy(TPM_DELEGATE_PUBLIC *dest, + TPM_DELEGATE_PUBLIC *src); + +/* + TPM_DELEGATE_SENSITIVE +*/ + +void TPM_DelegateSensitive_Init(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); +TPM_RESULT TPM_DelegateSensitive_Load(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); +void TPM_DelegateSensitive_Delete(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); + +TPM_RESULT TPM_DelegateSensitive_DecryptEncData(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + TPM_SIZED_BUFFER *sensitiveArea, + TPM_SYMMETRIC_KEY_TOKEN delegateKey); + +/* + TPM_DELEGATIONS +*/ + +void TPM_Delegations_Init(TPM_DELEGATIONS *tpm_delegations); +TPM_RESULT TPM_Delegations_Load(TPM_DELEGATIONS *tpm_delegations, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Delegations_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATIONS *tpm_delegations); +void TPM_Delegations_Delete(TPM_DELEGATIONS *tpm_delegations); + +void TPM_Delegations_Copy(TPM_DELEGATIONS *dest, + TPM_DELEGATIONS *src); +TPM_RESULT TPM_Delegations_CheckPermissionDelegation(TPM_DELEGATIONS *newDelegations, + TPM_DELEGATIONS *currentDelegations); +TPM_RESULT TPM_Delegations_CheckPermission(tpm_state_t *tpm_state, + TPM_DELEGATE_PUBLIC *delegatePublic, + TPM_ENT_TYPE entityType, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_Delegations_CheckOwnerPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_Delegations_CheckKeyPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal); + +/* + TPM_DELEGATE_OWNER_BLOB +*/ + +void TPM_DelegateOwnerBlob_Init(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); +TPM_RESULT TPM_DelegateOwnerBlob_Load(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateOwnerBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); +void TPM_DelegateOwnerBlob_Delete(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); + +/* + TPM_DELEGATE_KEY_BLOB +*/ + +void TPM_DelegateKeyBlob_Init(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); +TPM_RESULT TPM_DelegateKeyBlob_Load(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateKeyBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); +void TPM_DelegateKeyBlob_Delete(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); + +/* + TPM_FAMILY_TABLE +*/ + +void TPM_FamilyTable_Init(TPM_FAMILY_TABLE *tpm_family_table); +TPM_RESULT TPM_FamilyTable_Load(TPM_FAMILY_TABLE *tpm_family_table, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_FamilyTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag); +void TPM_FamilyTable_Delete(TPM_FAMILY_TABLE *tpm_family_table); + +TPM_RESULT TPM_FamilyTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag); +TPM_RESULT TPM_FamilyTable_GetEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID); +TPM_RESULT TPM_FamilyTable_GetEnabledEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID); +TPM_RESULT TPM_FamilyTable_IsSpace(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table); + +/* + TPM_FAMILY_TABLE_ENTRY +*/ + +void TPM_FamilyTableEntry_Init(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry); +TPM_RESULT TPM_FamilyTableEntry_Load(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_FamilyTableEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag); +TPM_RESULT TPM_FamilyTableEntry_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag); +void TPM_FamilyTableEntry_Delete(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry); + +/* + TPM_DELEGATE_TABLE +*/ + +void TPM_DelegateTable_Init(TPM_DELEGATE_TABLE *tpm_delegate_table); +TPM_RESULT TPM_DelegateTable_Load(TPM_DELEGATE_TABLE *tpm_delegate_table, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table); +void TPM_DelegateTable_Delete(TPM_DELEGATE_TABLE *tpm_delegate_table); + +TPM_RESULT TPM_DelegateTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table); +TPM_RESULT TPM_DelegateTable_GetRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex); +TPM_RESULT TPM_DelegateTable_GetValidRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex); + + +/* + TPM_DELEGATE_TABLE_ROW +*/ + +void TPM_DelegateTableRow_Init(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); +TPM_RESULT TPM_DelegateTableRow_Load(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateTableRow_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); +void TPM_DelegateTableRow_Delete(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); + + + + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_DelegateManage(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 TPM_Process_DelegateCreateKeyDelegation(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 TPM_Process_DelegateCreateOwnerDelegation(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 TPM_Process_DelegateLoadOwnerDelegation(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 TPM_Process_DelegateReadTable(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 TPM_Process_DelegateUpdateVerification(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 TPM_Process_DelegateVerifyDelegation(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); + +#endif diff --git a/src/tpm12/tpm_digest.c b/src/tpm12/tpm_digest.c new file mode 100644 index 0000000..0893912 --- /dev/null +++ b/src/tpm12/tpm_digest.c @@ -0,0 +1,162 @@ +/********************************************************************************/ +/* */ +/* Digest Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_digest.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_digest.h" + +/* TPM_Digest_Init resets a digest structure to zeros */ + +void TPM_Digest_Init(TPM_DIGEST tpm_digest) +{ + printf(" TPM_Digest_Init:\n"); + memset(tpm_digest, 0, TPM_DIGEST_SIZE); + return; +} + +/* TPM_Digest_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_Digest_Load(TPM_DIGEST tpm_digest, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Load:\n"); + rc = TPM_Loadn(tpm_digest, TPM_DIGEST_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Digest_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_Digest_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DIGEST tpm_digest) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + return rc; +} + +void TPM_Digest_Set(TPM_DIGEST tpm_digest) +{ + printf(" TPM_Digest_Set:\n"); + memset(tpm_digest, 0xff, TPM_DIGEST_SIZE); +} + +void TPM_Digest_Copy(TPM_DIGEST destination, const TPM_DIGEST source) +{ + printf(" TPM_Digest_Copy:\n"); + memcpy(destination, source, TPM_DIGEST_SIZE); + return; +} + +void TPM_Digest_XOR(TPM_DIGEST out, const TPM_DIGEST in1, const TPM_DIGEST in2) +{ + size_t i; + + printf(" TPM_Digest_XOR:\n"); + for (i = 0 ; i < TPM_DIGEST_SIZE ; i++) { + out[i] = in1[i] ^ in2[i]; + } + return; +} + +/* TPM_Digest_Compare() compares two digests, returning 0 if they are equal + */ + +TPM_RESULT TPM_Digest_Compare(const TPM_DIGEST expect, const TPM_DIGEST actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Compare:\n"); + rc = memcmp(expect, actual, TPM_DIGEST_SIZE); + if (rc != 0) { + printf("TPM_Digest_Compare: Error comparing digest\n"); + TPM_PrintFour(" TPM_Digest_Compare: Expect", expect); + TPM_PrintFour(" TPM_Digest_Compare: Actual", actual); + rc = TPM_AUTHFAIL; + } + return rc; +} + +void TPM_Digest_IsZero(TPM_BOOL *isZero, TPM_DIGEST tpm_digest) +{ + size_t i; + + printf(" TPM_Digest_IsZero:\n"); + for (i = 0, *isZero = TRUE ; (i < TPM_DIGEST_SIZE) && *isZero ; i++) { + if (tpm_digest[i] != 0) { + *isZero = FALSE; + } + } + return; +} + +#if 0 +void TPM_Digest_IsMinusOne(TPM_BOOL *isMinusOne, TPM_DIGEST tpm_digest) +{ + size_t i; + + printf(" TPM_Digest_IsMinusOne:\n"); + for (i = 0, *isMinusOne = TRUE ; (i < TPM_DIGEST_SIZE) && *isMinusOne ; i++) { + if (tpm_digest[i] != 0xff) { + *isMinusOne = FALSE; + } + } + return; +} +#endif diff --git a/src/tpm12/tpm_digest.h b/src/tpm12/tpm_digest.h new file mode 100644 index 0000000..6c3b342 --- /dev/null +++ b/src/tpm12/tpm_digest.h @@ -0,0 +1,64 @@ +/********************************************************************************/ +/* */ +/* Digest Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_digest.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_DIGEST_H +#define TPM_DIGEST_H + +#include "tpm_structures.h" +#include "tpm_store.h" + +void TPM_Digest_Init(TPM_DIGEST tpm_digest); +TPM_RESULT TPM_Digest_Load(TPM_DIGEST tpm_digest, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Digest_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DIGEST tpm_digest); + +void TPM_Digest_Set(TPM_DIGEST tpm_digest); +void TPM_Digest_Copy(TPM_DIGEST destination, const TPM_DIGEST source); +void TPM_Digest_XOR(TPM_DIGEST out, + const TPM_DIGEST in1, + const TPM_DIGEST in2); +TPM_RESULT TPM_Digest_Compare(const TPM_DIGEST expect, const TPM_DIGEST actual); +void TPM_Digest_IsZero(TPM_BOOL *isZero, TPM_DIGEST tpm_digest); +#if 0 +void TPM_Digest_IsMinusOne(TPM_BOOL *isMinusOne, TPM_DIGEST tpm_digest); +#endif + +#endif diff --git a/src/tpm12/tpm_error.c b/src/tpm12/tpm_error.c new file mode 100644 index 0000000..b4c47d8 --- /dev/null +++ b/src/tpm12/tpm_error.c @@ -0,0 +1,43 @@ +/********************************************************************************/ +/* */ +/* Error Response */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_error.c 4071 2010-04-29 19:26:45Z 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 "tpm_error.h" + diff --git a/src/tpm12/tpm_global.c b/src/tpm12/tpm_global.c new file mode 100644 index 0000000..411adde --- /dev/null +++ b/src/tpm12/tpm_global.c @@ -0,0 +1,252 @@ +/********************************************************************************/ +/* */ +/* Global Variables */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_global.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <string.h> +#include <stdio.h> + +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_nvfile.h" +#include "tpm_nvram.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_startup.h" +#include "tpm_structures.h" + + +#include "tpm_global.h" + +/* state for the TPM's */ +tpm_state_t *tpm_instances[TPMS_MAX]; + +/* TPM_Global_Init initializes the tpm_state to default values. + + It does not load any data from or store data to NVRAM +*/ + +TPM_RESULT TPM_Global_Init(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf("TPM_Global_Init: TPMs %lu\n", + (unsigned long)sizeof(tpm_instances)/sizeof(tpm_state_t *)); + /* initialize the TPM_STANY_FLAGS structure */ + if (rc == 0) { + /* set the structure to 0 for security, clean out old secrets */ + memset(tpm_state, 0 , sizeof(tpm_state_t)); + /* the virtual TPM number NOTE: This must be done early as it is used to construct + nn.permall file names */ + tpm_state->tpm_number = TPM_ILLEGAL_INSTANCE_HANDLE; + /* initialize the TPM_PERMANENT_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_PERMANENT_FLAGS\n"); + TPM_PermanentFlags_Init(&(tpm_state->tpm_permanent_flags)); + /* initialize the TPM_STCLEAR_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_STCLEAR_FLAGS\n"); + TPM_StclearFlags_Init(&(tpm_state->tpm_stclear_flags)); + /* initialize the TPM_STANY_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_STANY_FLAGS\n"); + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + /* initialize TPM_PERMANENT_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_PERMANENT_DATA\n"); + rc = TPM_PermanentData_Init(&(tpm_state->tpm_permanent_data), TRUE); + } + if (rc == 0) { + /* initialize TPM_STCLEAR_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_STCLEAR_DATA\n"); + TPM_StclearData_Init(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + TRUE); /* initialize the PCR's */ + /* initialize TPM_STANY_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_STANY_DATA\n"); + rc = TPM_StanyData_Init(&(tpm_state->tpm_stany_data)); + } + /* initialize the TPM_KEY_HANDLE_LIST structure */ + if (rc == 0) { + printf("TPM_Global_Init: Initializing TPM_KEY_HANDLE_LIST\n"); + TPM_KeyHandleEntries_Init(tpm_state->tpm_key_handle_entries); + /* initialize the SHA1 thread context */ + tpm_state->sha1_context = NULL; + /* initialize the TIS SHA1 thread context */ + tpm_state->sha1_context_tis = NULL; + tpm_state->transportHandle = 0; + printf("TPM_Global_Init: Initializing TPM_NV_INDEX_ENTRIES\n"); + TPM_NVIndexEntries_Init(&(tpm_state->tpm_nv_index_entries)); + } + /* comes up in limited operation mode */ + /* shutdown is set on a self test failure, before calling TPM_Global_Init() */ + if (rc == 0) { + printf(" TPM_Global_Init: Set testState to %u \n", TPM_TEST_STATE_LIMITED); + tpm_state->testState = TPM_TEST_STATE_LIMITED; + } + else { + printf(" TPM_Global_Init: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +#if 0 +/* TPM_Global_Load() loads the tpm_state_t global structures for the TPM instance from NVRAM. + + tpm_state->tpm_number must be set by the caller. + + Returns + + 0 on success. + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_Global_Load(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf("TPM_Global_Load:\n"); + /* TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined space. */ + if (rc == 0) { + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + if (rc == 0) { + rc = TPM_VolatileAll_NVLoad(tpm_state); + } + return rc; +} + +/* TPM_Global_Store() store the tpm_state_t global structure for the TPM instance to NVRAM + + tpm_state->tpm_number must be set by the caller. +*/ + +TPM_RESULT TPM_Global_Store(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Global_Store:\n"); + if (rc == 0) { + rc = TPM_PermanentAll_NVStore(tpm_state, TRUE, 0); + } + if (rc == 0) { + rc = TPM_VolatileAll_NVStore(tpm_state); + } + return rc; +} +#endif + +/* TPM_Global_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Global_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Global_Delete(tpm_state_t *tpm_state) +{ + printf(" TPM_Global_Delete:\n"); + if (tpm_state != NULL) { + /* TPM_PERMANENT_FLAGS have no allocated memory or secrets */ + /* TPM_STCLEAR_FLAGS have no allocated memory or secrets */ + /* TPM_STANY_FLAGS have no allocated memory or secrets */ + printf(" TPM_Global_Delete: Deleting TPM_PERMANENT_DATA\n"); + TPM_PermanentData_Delete(&(tpm_state->tpm_permanent_data), TRUE); + printf(" TPM_Global_Delete: Deleting TPM_STCLEAR_DATA\n"); + TPM_StclearData_Delete(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + TRUE); /* reset the PCR's */ + printf(" TPM_Global_Delete: Deleting TPM_STANY_DATA\n"); + TPM_StanyData_Delete(&(tpm_state->tpm_stany_data)); + printf(" TPM_Global_Delete: Deleting key handle entries\n"); + TPM_KeyHandleEntries_Delete(tpm_state->tpm_key_handle_entries); + printf(" TPM_Global_Delete: Deleting SHA1 contexts\n"); + TPM_SHA1Delete(&(tpm_state->sha1_context)); + TPM_SHA1Delete(&(tpm_state->sha1_context_tis)); + TPM_NVIndexEntries_Delete(&(tpm_state->tpm_nv_index_entries)); + } + return; +} + + +/* TPM_Global_GetPhysicalPresence() returns 'physicalPresence' TRUE if either TPM_STCLEAR_FLAGS -> + physicalPresence is TRUE or hardware physical presence is indicated. + + The physicalPresenceHWEnable and physicalPresenceCMDEnable flags MUST mask their respective + signals before further processing. The hardware signal, if enabled by the + physicalPresenceHWEnable flag, MUST be logically ORed with the PhysicalPresence flag, if enabled, + to obtain the final physical presence value used to allow or disallow local commands. +*/ + +TPM_RESULT TPM_Global_GetPhysicalPresence(TPM_BOOL *physicalPresence, + const tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + *physicalPresence = FALSE; + + /* is CMD physical presence enabled */ + printf(" TPM_Global_GetPhysicalPresence: physicalPresenceCMDEnable is %02x\n", + tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable); + if (tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable) { + printf(" TPM_Global_GetPhysicalPresence: physicalPresence flag is %02x\n", + tpm_state->tpm_stclear_flags.physicalPresence); + /* if enabled, check for physicalPresence set by the command ordinal */ + *physicalPresence = tpm_state->tpm_stclear_flags.physicalPresence; + } + + /* if the software flag is true, result is true, no need to check the hardware */ + /* if the TPM_STCLEAR_FLAGS flag is FALSE, check the hardware */ + if (!(*physicalPresence)) { + printf(" TPM_Global_GetPhysicalPresence: physicalPresenceHWEnable is %02x\n", + tpm_state->tpm_permanent_flags.physicalPresenceHWEnable); + /* if physicalPresenceHWEnable is FALSE, the hardware signal is disabled */ + if (tpm_state->tpm_permanent_flags.physicalPresenceHWEnable) { + /* if enabled, check the hardware signal */ + rc = TPM_IO_GetPhysicalPresence(physicalPresence, tpm_state->tpm_number); + printf(" TPM_Global_GetPhysicalPresence: physicalPresence HW is %02x\n", + *physicalPresence); + } + } + printf(" TPM_Global_GetPhysicalPresence: physicalPresence is %02x\n", + *physicalPresence); + return rc; +} + diff --git a/src/tpm12/tpm_global.h b/src/tpm12/tpm_global.h new file mode 100644 index 0000000..09cb7eb --- /dev/null +++ b/src/tpm12/tpm_global.h @@ -0,0 +1,103 @@ +/********************************************************************************/ +/* */ +/* Global Variables */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_global.h 4285 2011-01-17 21:27:05Z 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. */ +/********************************************************************************/ + +#ifndef TPM_GLOBAL_H +#define TPM_GLOBAL_H + +#include "tpm_nvram_const.h" +#include "tpm_types.h" +#include "tpm_structures.h" + +#define TPM_TEST_STATE_LIMITED 1 /* limited operation mode */ +#define TPM_TEST_STATE_FULL 2 /* full operation mode */ +#define TPM_TEST_STATE_FAILURE 3 /* failure mode */ + +typedef struct tdTPM_STATE +{ + /* the number of the virtual TPM */ + uint32_t tpm_number; + /* 7.1 TPM_PERMANENT_FLAGS */ + TPM_PERMANENT_FLAGS tpm_permanent_flags; + /* 7.2 TPM_STCLEAR_FLAGS */ + TPM_STCLEAR_FLAGS tpm_stclear_flags; + /* 7.3 TPM_STANY_FLAGS */ + TPM_STANY_FLAGS tpm_stany_flags; + /* 7.4 TPM_PERMANENT_DATA */ + TPM_PERMANENT_DATA tpm_permanent_data; + /* 7.5 TPM_STCLEAR_DATA */ + TPM_STCLEAR_DATA tpm_stclear_data; + /* 7.6 TPM_STANY_DATA */ + TPM_STANY_DATA tpm_stany_data; + /* 5.6 TPM_KEY_HANDLE_ENTRY */ + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entries[TPM_KEY_HANDLES]; + /* Context for SHA1 functions */ + void *sha1_context; + void *sha1_context_tis; + TPM_TRANSHANDLE transportHandle; /* non-zero if the context was set up in a transport + session */ + /* self test shutdown */ + uint32_t testState; + /* NVRAM volatile data marker. Cleared at TPM_Startup(ST_Clear), it holds all indexes which + have been read. The index not being present indicates that some volatile fields should be + cleared at first read. */ + TPM_NV_INDEX_ENTRIES tpm_nv_index_entries; + /* NOTE: members added here should be initialized by TPM_Global_Init() and possibly added to + TPM_SaveState_Load() and TPM_SaveState_Store() */ +} tpm_state_t; + +/* state for the TPM */ +extern tpm_state_t *tpm_instances[]; + + +/* + tpm_state_t +*/ + +TPM_RESULT TPM_Global_Init(tpm_state_t *tpm_state); +#if 0 +TPM_RESULT TPM_Global_Load(tpm_state_t *tpm_state); +TPM_RESULT TPM_Global_Store(tpm_state_t *tpm_state); +#endif +void TPM_Global_Delete(tpm_state_t *tpm_state); + + +TPM_RESULT TPM_Global_GetPhysicalPresence(TPM_BOOL *physicalPresence, + const tpm_state_t *tpm_state); + +#endif diff --git a/src/tpm12/tpm_identity.c b/src/tpm12/tpm_identity.c new file mode 100644 index 0000000..742bccd --- /dev/null +++ b/src/tpm12/tpm_identity.c @@ -0,0 +1,1448 @@ +/********************************************************************************/ +/* */ +/* TPM Identity Handling */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_identity.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_ver.h" +#include "tpm_identity.h" + +/* + TPM_EK_BLOB +*/ + +/* TPM_EKBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlob_Init(TPM_EK_BLOB *tpm_ek_blob) +{ + printf(" TPM_EKBlob_Init:\n"); + tpm_ek_blob->ekType = 0; + TPM_SizedBuffer_Init(&(tpm_ek_blob->blob)); + return; +} + +/* TPM_EKBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlob_Init() + After use, call TPM_EKBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlob_Load(TPM_EK_BLOB *tpm_ek_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlob_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB, stream, stream_size); + } + /* load ekType */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_ek_blob->ekType), stream, stream_size); + } + /* load blob */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_ek_blob->blob), stream, stream_size); + } + return rc; +} + +#if 0 +/* TPM_EKBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB *tpm_ek_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlob_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_ek_blob->ekType); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_ek_blob->blob)); + } + return rc; +} +#endif + +/* TPM_EKBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlob_Delete(TPM_EK_BLOB *tpm_ek_blob) +{ + printf(" TPM_EKBlob_Delete:\n"); + if (tpm_ek_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_ek_blob->blob)); + TPM_EKBlob_Init(tpm_ek_blob); + } + return; +} + +/* + TPM_EK_BLOB_ACTIVATE +*/ + +/* TPM_EKBlobActivate_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlobActivate_Init(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + printf(" TPM_EKBlobActivate_Init:\n"); + TPM_SymmetricKey_Init(&(tpm_ek_blob_activate->sessionKey)); + TPM_Digest_Init(tpm_ek_blob_activate->idDigest); + TPM_PCRInfoShort_Init(&(tpm_ek_blob_activate->pcrInfo)); + return; +} + +/* TPM_EKBlobActivate_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlobActivate_Init() + After use, call TPM_EKBlobActivate_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlobActivate_Load(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobActivate_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB_ACTIVATE, stream, stream_size); + } + /* load sessionKey */ + if (rc == 0) { + rc = TPM_SymmetricKey_Load(&(tpm_ek_blob_activate->sessionKey), stream, stream_size); + } + /* load idDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_ek_blob_activate->idDigest, stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_ek_blob_activate->pcrInfo), stream, stream_size, FALSE); + } + return rc; +} + +#if 0 +/* TPM_EKBlobActivate_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlobActivate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobActivate_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB_ACTIVATE); + } + /* store sessionKey */ + if (rc == 0) { + rc = TPM_SymmetricKey_Store(sbuffer, &(tpm_ek_blob_activate->sessionKey)); + } + /* store idDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_ek_blob_activate->idDigest); + } + /* store pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_ek_blob_activate->pcrInfo), FALSE); + } + return rc; +} +#endif + +/* TPM_EKBlobActivate_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlobActivate_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlobActivate_Delete(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + printf(" TPM_EKBlobActivate_Delete:\n"); + if (tpm_ek_blob_activate != NULL) { + TPM_SymmetricKey_Delete(&(tpm_ek_blob_activate->sessionKey)); + TPM_PCRInfoShort_Delete(&(tpm_ek_blob_activate->pcrInfo)); + TPM_EKBlobActivate_Init(tpm_ek_blob_activate); + } + return; +} + +/* + TPM_EK_BLOB_AUTH +*/ + +#if 0 +/* TPM_EKBlobAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlobAuth_Init(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + printf(" TPM_EKBlobAuth_Init:\n"); + TPM_Secret_Init(tpm_ek_blob_auth->authValue); + return; +} + +/* TPM_EKBlobAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlobAuth_Init() + After use, call TPM_EKBlobAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlobAuth_Load(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobAuth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB_AUTH, stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_ek_blob_auth->authValue, stream, stream_size); + } + return rc; +} + +/* TPM_EKBlobAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlobAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobAuth_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB_AUTH); + } + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_ek_blob_auth->authValue); + } + return rc; +} + +/* TPM_EKBlobAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlobAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlobAuth_Delete(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + printf(" TPM_EKBlobAuth_Delete:\n"); + if (tpm_ek_blob_auth != NULL) { + TPM_EKBlobAuth_Init(tpm_ek_blob_auth); + } + return; +} +#endif + +/* + TPM_IDENTITY_CONTENTS +*/ + +/* TPM_IdentityContents_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_IdentityContents_Init(TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + printf(" TPM_IdentityContents_Init:\n"); + TPM_StructVer_Init(&(tpm_identity_contents->ver)); + tpm_identity_contents->ordinal = TPM_ORD_MakeIdentity; + TPM_Digest_Init(tpm_identity_contents->labelPrivCADigest); + TPM_Pubkey_Init(&(tpm_identity_contents->identityPubKey)); + return; +} + +/* TPM_IdentityContents_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_IdentityContents_Init() + After use, call TPM_IdentityContents_Delete() to free memory + + NOTE: Never called. +*/ +#if 0 +TPM_RESULT TPM_IdentityContents_Load(TPM_IDENTITY_CONTENTS *tpm_identity_contents, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_IdentityContents_Load:\n"); + /* load ver */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_identity_contents->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_identity_contents->ver)); + } + /* load ordinal */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_identity_contents->ordinal), stream, stream_size); + } + /* load labelPrivCADigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_identity_contents->labelPrivCADigest, stream, stream_size); + } + /* load identityPubKey */ + if (rc == 0) { + rc = TPM_Pubkey_Load(&(tpm_identity_contents->identityPubKey), stream, stream_size); + } + return rc; +} +#endif + +/* TPM_IdentityContents_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_IdentityContents_Store(TPM_STORE_BUFFER *sbuffer, + TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + TPM_RESULT rc = 0; + + printf(" TPM_IdentityContents_Store:\n"); + /* store ver */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_identity_contents->ver)); + } + /* store ordinal */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_identity_contents->ordinal); + } + /* store labelPrivCADigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_identity_contents->labelPrivCADigest); + } + /* store identityPubKey */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_identity_contents->identityPubKey)); + } + return rc; +} + +/* TPM_IdentityContents_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_IdentityContents_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_IdentityContents_Delete(TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + printf(" TPM_IdentityContents_Delete:\n"); + if (tpm_identity_contents != NULL) { + TPM_Pubkey_Delete(&(tpm_identity_contents->identityPubKey)); + TPM_IdentityContents_Init(tpm_identity_contents); + } + return; +} + +/* + TPM_ASYM_CA_CONTENTS +*/ + +/* TPM_AsymCaContents_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AsymCaContents_Init(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + printf(" TPM_AsymCaContents_Init:\n"); + TPM_SymmetricKey_Init(&(tpm_asym_ca_contents->sessionKey)); + TPM_Digest_Init(tpm_asym_ca_contents->idDigest); + return; +} + +/* TPM_AsymCaContents_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AsymCaContents_Init() + After use, call TPM_AsymCaContents_Delete() to free memory +*/ + +TPM_RESULT TPM_AsymCaContents_Load(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AsymCaContents_Load:\n"); + if (rc == 0) { + rc = TPM_SymmetricKey_Load(&(tpm_asym_ca_contents->sessionKey), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Digest_Load(tpm_asym_ca_contents->idDigest, stream, stream_size); + } + return rc; +} + +#if 0 +/* TPM_AsymCaContents_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AsymCaContents_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AsymCaContents_Store:\n"); + if (rc == 0) { + rc = TPM_SymmetricKey_Store(sbuffer, &(tpm_asym_ca_contents->sessionKey)); + } + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_asym_ca_contents->idDigest); + } + return rc; +} +#endif + +/* TPM_AsymCaContents_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AsymCaContents_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AsymCaContents_Delete(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + printf(" TPM_AsymCaContents_Delete:\n"); + if (tpm_asym_ca_contents != NULL) { + TPM_SymmetricKey_Delete(&(tpm_asym_ca_contents->sessionKey)); + TPM_AsymCaContents_Init(tpm_asym_ca_contents); + } + return; +} + + + + + + +/* + Processing Functions +*/ + +/* 15.1 TPM_MakeIdentity rev 114 + + Generate a new Attestation Identity Key (AIK) + + labelPrivCADigest identifies the privacy CA that the owner expects to be the target CA for the + AIK. The selection is not enforced by the TPM. It is advisory only. It is included because the + TSS cannot be trusted to send the AIK to the correct privacy CA. The privacy CA can use this + parameter to validate that it is the target privacy CA and label intended by the TPM owner at the + time the key was created. The label can be used to indicate an application purpose. + + The public key of the new TPM identity SHALL be identityPubKey. The private key of the new TPM + identity SHALL be tpm_signature_key. + + Properties of the new identity + + TPM_PUBKEY identityPubKey This SHALL be the public key of a previously unused asymmetric key + pair. + + TPM_STORE_ASYMKEY tpm_signature_key This SHALL be the private key that forms a pair with + identityPubKey and SHALL be extant only in a TPM-shielded location. + + This capability also generates a TPM_KEY containing the tpm_signature_key. + + If identityPubKey is stored on a platform it SHALL exist only in storage to which access is + controlled and is available to authorized entities. +*/ + +TPM_RESULT TPM_Process_MakeIdentity(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENCAUTH identityAuth; /* Encrypted usage authorization data for the new identity + */ + TPM_CHOSENID_HASH labelPrivCADigest; /* The digest of the identity label and privacy CA + chosen for the new TPM identity. */ + TPM_KEY idKeyParams; /* Structure containing all parameters of new identity + key. pubKey.keyLength & idKeyParams.encData are both 0 + MAY be TPM_KEY12 */ + TPM_AUTHHANDLE srkAuthHandle; /* The authorization handle used for SRK authorization. */ + TPM_NONCE srknonceOdd; /* Nonce generated by system associated with srkAuthHandle + */ + TPM_BOOL continueSrkSession = TRUE; /* Ignored */ + TPM_AUTHDATA srkAuth; /* The authorization digest for the inputs and the SRK. HMAC + key: srk.usageAuth. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner + authorization. Session type MUST be OSAP. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner. HMAC key: + ownerAuth. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL srkAuthHandleValid = FALSE; + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *srk_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */ + TPM_SECRET *srkHmacKey; + TPM_SECRET *hmacKey; + TPM_SECRET a1Auth; + TPM_STORE_ASYMKEY *idKeyStoreAsymkey; + TPM_IDENTITY_CONTENTS idContents; + TPM_DIGEST h1Digest; /* digest of TPM_IDENTITY_CONTENTS structure */ + int ver; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY idKey; /* The newly created identity key. MAY be TPM_KEY12 + */ + TPM_SIZED_BUFFER identityBinding; /* Signature of TPM_IDENTITY_CONTENTS using + idKey.private. */ + printf("TPM_Process_MakeIdentity: Ordinal Entry\n"); + TPM_Key_Init(&idKeyParams); /* freed @1 */ + TPM_Key_Init(&idKey); /* freed @2 */ + TPM_SizedBuffer_Init(&identityBinding); /* freed @3 */ + TPM_IdentityContents_Init(&idContents); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get identityAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(identityAuth, &command, ¶mSize); + } + /* get labelPrivCADigest parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(labelPrivCADigest, &command, ¶mSize); + } + /* get idKeyParams parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&idKeyParams, &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_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&srkAuthHandle, + &srkAuthHandleValid, + srknonceOdd, + &continueSrkSession, + srkAuth, + &command, ¶mSize); + printf("TPM_Process_MakeIdentity: srkAuthHandle %08x\n", srkAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_MakeIdentity: 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) { + srkAuthHandleValid = FALSE; + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the idKeyParams parameters for the key description */ + /* a. If the algorithm type is RSA the key length MUST be a minimum of 2048 and MUST use the + default exponent. For interoperability the key length SHOULD be 2048 */ + /* b. If the algorithm type is other than RSA the strength provided by the key MUST be + comparable to RSA 2048 */ + /* c. If the TPM is not designed to create a key of the requested type, return the error code + TPM_BAD_KEY_PROPERTY */ + /* d. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then */ + /* i. If authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckProperties(&ver, &idKeyParams, 2048, + tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_Process_MakeIdentity: key parameters v = %d\n", ver); + } + /* 2. Use authHandle to verify that the Owner authorized all TPM_MakeIdentity input + parameters. */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. Use srkAuthHandle to verify that the SRK owner authorized all TPM_MakeIdentity input + parameters. */ + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData + (&srk_auth_session_data, + &srkHmacKey, + tpm_state, + srkAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + &(tpm_state->tpm_permanent_data.srk), + /* OIAP */ + &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->usageAuth), + /* OSAP */ + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *srkHmacKey, /* HMAC key */ + inParamDigest, + srk_auth_session_data, /* authorization session */ + srknonceOdd, /* Nonce generated by system + associated with authHandle */ + continueSrkSession, + srkAuth); /* Authorization digest for input */ + } + /* if there is no SRK authorization, check that the SRK authDataUsage is TPM_AUTH_NEVER */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (tpm_state->tpm_permanent_data.srk.authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_MakeIdentity: Error, SRK authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 4. Verify that idKeyParams -> keyUsage is TPM_KEY_IDENTITY. If it is not, return + TPM_INVALID_KEYUSAGE */ + /* NOTE: TPM_KEY_IDENTITY keys must use TPM_SS_RSASSAPKCS1v15_SHA1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Checking key parameters\n"); + if (idKeyParams.keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_Process_MakeIdentity: Error, " + "idKeyParams keyUsage %08x should be TPM_KEY_IDENTITY\n", + idKeyParams.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Verify that idKeyParams -> keyFlags -> migratable is FALSE. If it is not, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (idKeyParams.keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_MakeIdentity: Error, " + "idKeyParams keyFlags %08x cannot be migratable\n", + idKeyParams.keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Create a1 by decrypting identityAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + identityAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 7. Set continueAuthSession and continueSRKSession to FALSE. */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + continueSrkSession = FALSE; + /* 8. Determine the structure version */ + /* a. If idKeyParams -> tag is TPM_TAG_KEY12 */ + /* i. Set V1 to 2 */ + /* ii. Create idKey a TPM_KEY12 structure using idKeyParams as the default values for the + structure */ + /* b. If idKeyParams -> ver is 1.1 */ + /* i. Set V1 to 1 */ + /* ii. Create idKey a TPM_KEY structure using idKeyParams as the default values for the + structure */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* NOTE The creation determination is done by TPM_Key_GenerateRSA() */ + } + /* 9. Set the digestAtCreation values for pcrInfo */ + /* NOTE Done as the key is generated */ + /* a. For PCR_INFO_LONG include the locality of the current command */ + /* 10. Create an asymmetric key pair (identityPubKey and tpm_signature_key) using a + TPM-protected capability, in accordance with the algorithm specified in idKeyParams */ + if (returnCode == TPM_SUCCESS) { + /* generate the key pair, create the tpm_store_asymkey cache, copy key parameters, create + tpm_pcr_info cache, copies pcr parameters, sets digestAtCreation, sets pubKey, serializes + pcrInfo + + does not set encData */ + printf("TPM_Process_MakeIdentity: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&idKey, + tpm_state, + &(tpm_state->tpm_permanent_data.srk), /* parent key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + idKeyParams.keyUsage, + idKeyParams.keyFlags, + idKeyParams.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(idKeyParams.algorithmParms), /* TPM_KEY_PARMS */ + idKeyParams.tpm_pcr_info, /* TPM_PCR_INFO */ + idKeyParams.tpm_pcr_info_long);/* TPM_PCR_INFO_LONG */ + + } + /* 11. Ensure that the authorization information in A1 is properly stored in the idKey as + usageAuth. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&idKeyStoreAsymkey, + &idKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(idKeyStoreAsymkey->usageAuth, a1Auth); + /* 12. Attach identityPubKey and tpm_signature_key to idKey */ + /* Note: Done as the key is generated */ + /* 13. Set idKey -> migrationAuth to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(idKeyStoreAsymkey->migrationAuth, tpm_state->tpm_permanent_data.tpmProof); + /* 14. Ensure that all TPM_PAYLOAD_TYPE structures identity this key as TPM_PT_ASYM */ + /* NOTE Done as the key is generated */ + } + /* 15. Encrypt the private portion of idKey using the SRK as the parent key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Encrypting key private part with SRK\n"); + returnCode = TPM_Key_GenerateEncData(&idKey, &(tpm_state->tpm_permanent_data.srk)); + } + /* 16. Create a TPM_IDENTITY_CONTENTS structure named idContents using labelPrivCADigest and the + information from idKey */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(idContents.labelPrivCADigest, labelPrivCADigest); + returnCode = TPM_Pubkey_Set(&(idContents.identityPubKey), &idKey); + } + /* 17. Sign idContents using tpm_signature_key and TPM_SS_RSASSAPKCS1v15_SHA1. Store the result + in identityBinding. */ + /* NOTE: TPM_Key_CheckProperties() verified TPM_SS_RSASSAPKCS1v15_SHA1 */ + /* serialize tpm_identity_contents and hash the results*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1Digest, + &idContents, + (TPM_STORE_FUNCTION_T)TPM_IdentityContents_Store); + } + /* sign the digest */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Signing digest of TPM_IDENTITY_CONTENTS\n"); + returnCode = TPM_RSASignToSizedBuffer(&identityBinding, h1Digest, TPM_DIGEST_SIZE, &idKey); + } +#if 0 /* NOTE Debug code to reverse the signature */ + if (returnCode == TPM_SUCCESS) { + unsigned char *message = NULL; + unsigned char *narr = NULL; + uint32_t nbytes; + unsigned char *earr = NULL; + uint32_t ebytes; + if (returnCode == 0) { + returnCode = TPM_Malloc(&message, identityBinding.size); /* freed @10 */ + } + if (returnCode == 0) { + returnCode = TPM_Key_GetPublicKey(&nbytes, &narr, &idKey); + } + if (returnCode == 0) { + returnCode = TPM_Key_GetExponent(&ebytes, &earr, &idKey); + } + if (returnCode == 0) { + returnCode = TPM_RSAPublicEncryptRaw(message, /* output */ + identityBinding.size, + identityBinding.buffer, /* input */ + identityBinding.size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + free(message); /* @10 */ + } +#endif + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_MakeIdentity: 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 idKey */ + returnCode = TPM_Key_Store(response, &idKey); + } + if (returnCode == TPM_SUCCESS) { + /* return identityBinding */ + returnCode = TPM_SizedBuffer_Store(response, &identityBinding); + /* 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_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *srkHmacKey, /* owner HMAC key */ + srk_auth_session_data, + outParamDigest, + srknonceOdd, + continueSrkSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueSrkSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueSrkSession) && + srkAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, srkAuthHandle); + } + /* 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_Key_Delete(&idKeyParams); /* freed @1 */ + TPM_Key_Delete(&idKey); /* freed @2 */ + TPM_SizedBuffer_Delete(&identityBinding); /* freed @3 */ + TPM_IdentityContents_Delete(&idContents); /* freed @4 */ + return rcf; +} + +/* 15.2 TPM_ActivateIdentity rev 107 + + The purpose of TPM_ActivateIdentity is to twofold. The first purpose is to obtain assurance that + the credential in the TPM_SYM_CA_ATTESTATION is for this TPM. The second purpose is to obtain the + session key used to encrypt the TPM_IDENTITY_CREDENTIAL. + + The command TPM_ActivateIdentity activates a TPM identity created using the command + TPM_MakeIdentity. + + The command assumes the availability of the private key associated with the identity. The command + will verify the association between the keys during the process. + + The command will decrypt the input blob and extract the session key and verify the connection + between the public and private keys. The input blob can be in 1.1 or 1.2 format. +*/ + +TPM_RESULT TPM_Process_ActivateIdentity(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 idKeyHandle; /* handle of identity key to be activated */ + TPM_SIZED_BUFFER blob; /* The encrypted ASYM_CA_CONTENTS or TPM_EK_BLOB */ + TPM_AUTHHANDLE idKeyAuthHandle; /* The authorization handle used for ID key + authorization. */ + TPM_NONCE idKeynonceOdd; /* Nonce generated by system associated with idKeyAuthHandle + */ + TPM_BOOL continueIdKeySession = TRUE; /* Continue usage flag for idKeyAuthHandle. */ + TPM_AUTHDATA idKeyAuth; /* The authorization digest for the inputs and ID key. HMAC + key: idKey.usageAuth. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL idKeyAuthHandleValid = FALSE; + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *id_key_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */ + TPM_SECRET *idKeyHmacKey; + TPM_SECRET *hmacKey; + TPM_KEY *idKey; /* Identity key to be activated */ + TPM_SECRET *idKeyUsageAuth; + TPM_BOOL idPCRStatus; + TPM_DIGEST h1Digest; /* digest of public key in idKey */ + unsigned char *b1Blob = NULL; /* decrypted blob */ + uint32_t b1BlobLength = 0; /* actual valid data */ + TPM_STRUCTURE_TAG hTag; /* b1 tag in host byte order */ + int vers = 0; /* version of blob */ + unsigned char *stream; + uint32_t stream_size; + TPM_EK_BLOB b1EkBlob; + TPM_ASYM_CA_CONTENTS b1AsymCaContents; + TPM_SYMMETRIC_KEY *k1 = NULL; + TPM_EK_BLOB_ACTIVATE a1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SYMMETRIC_KEY symmetricKey; /* The decrypted symmetric key. */ + + printf("TPM_Process_ActivateIdentity: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&blob); /* freed @1 */ + TPM_SymmetricKey_Init(&symmetricKey); /* freed @2 */ + TPM_AsymCaContents_Init(&b1AsymCaContents); /* freed @4 */ + TPM_EKBlob_Init(&b1EkBlob); /* freed @5 */ + TPM_EKBlobActivate_Init(&a1); /* freed @6 */ + /* + get inputs + */ + /* get idKey parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&idKeyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get blob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&blob, &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_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&idKeyAuthHandle, + &idKeyAuthHandleValid, + idKeynonceOdd, + &continueIdKeySession, + idKeyAuth, + &command, ¶mSize); + printf("TPM_Process_ActivateIdentity: idKeyAuthHandle %08x\n", idKeyAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ActivateIdentity: 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) { + idKeyAuthHandleValid = FALSE; + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Using the authHandle field, validate the owner's authorization to execute the command and + all of the incoming parameters. */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Using the idKeyAuthHandle, validate the authorization to execute command and all of the + incoming parameters */ + /* get the idKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&idKey, &idPCRStatus, tpm_state, idKeyHandle, + FALSE, /* not r/o, using to authenticate */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&idKeyUsageAuth, idKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&id_key_auth_session_data, + &idKeyHmacKey, + tpm_state, + idKeyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + idKey, + idKeyUsageAuth, /* OIAP */ + idKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *idKeyHmacKey, /* HMAC key */ + inParamDigest, + id_key_auth_session_data, /* authorization session */ + idKeynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueIdKeySession, + idKeyAuth); /* Authorization digest for input */ + } + /* if there is no idKey authorization, check that the idKey -> authDataUsage is TPM_AUTH_NEVER + */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (idKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ActivateIdentity: Error, ID key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. Validate that the idKey is the public key of a valid TPM identity by checking that + idKeyHandle -> keyUsage is TPM_KEY_IDENTITY. Return TPM_BAD_PARAMETER on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: Checking for identity key\n"); + if (idKey->keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_Process_ActivateIdentity: Error, keyUsage %04hx must be TPM_KEY_IDENTITY\n", + idKey->keyUsage); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 4. Create H1 the digest of a TPM_PUBKEY derived from idKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GeneratePubkeyDigest(h1Digest, idKey); + } + /* 5. Decrypt blob creating B1 using PRIVEK as the decryption key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: Decrypting blob with EK\n"); + returnCode = TPM_RSAPrivateDecryptMalloc(&b1Blob, /* decrypted data */ + &b1BlobLength, /* actual size of b1 data */ + blob.buffer, + blob.size, + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* 6. Determine the type and version of B1 */ + if (returnCode == TPM_SUCCESS) { + stream = b1Blob; /* b1 must be preserved for the free */ + stream_size = b1BlobLength; + /* convert possible tag to uint16_t */ + hTag = ntohs(*(TPM_STRUCTURE_TAG *)b1Blob); + /* a. If B1 -> tag is TPM_TAG_EK_BLOB then */ + if (hTag == TPM_TAG_EK_BLOB) { + /* i. B1 is a TPM_EK_BLOB */ + printf("TPM_Process_ActivateIdentity: b1 is TPM_EK_BLOB\n"); + vers = 2; + returnCode = TPM_EKBlob_Load(&b1EkBlob, &stream, &stream_size); + } + /* b. Else */ + else { + /* i. B1 is a TPM_ASYM_CA_CONTENTS. As there is no tag for this structure it is possible + for the TPM to make a mistake here but other sections of the structure undergo + validation */ + printf("TPM_Process_ActivateIdentity: b1 is TPM_ASYM_CA_CONTENTS\n"); + vers = 1; + returnCode = TPM_AsymCaContents_Load(&b1AsymCaContents, &stream, &stream_size); + } + } + /* 7. If B1 is a version 1.1 TPM_ASYM_CA_CONTENTS then */ + if ((returnCode == TPM_SUCCESS) && (vers == 1)) { + /* a. Compare H1 to B1 -> idDigest on mismatch return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(h1Digest, b1AsymCaContents.idDigest); + if (returnCode != 0) { + printf("TPM_Process_ActivateIdentity: Error " + "comparing TPM_ASYM_CA_CONTENTS idDigest\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set K1 to B1 -> sessionKey */ + if (returnCode == TPM_SUCCESS) { + k1 = &(b1AsymCaContents.sessionKey); + } + } + /* 8. If B1 is a TPM_EK_BLOB then */ + if ((returnCode == TPM_SUCCESS) && (vers == 2)) { + /* a. Validate that B1 -> ekType is TPM_EK_TYPE_ACTIVATE, return TPM_BAD_TYPE if not. */ + if (returnCode == TPM_SUCCESS) { + if (b1EkBlob.ekType != TPM_EK_TYPE_ACTIVATE) { + printf("TPM_Process_ActivateIdentity: Error, " + "TPM_EK_BLOB not ekType TPM_EK_TYPE_ACTIVATE\n"); + returnCode = TPM_BAD_TYPE; + } + } + /* b. Assign A1 as a TPM_EK_BLOB_ACTIVATE structure from B1 -> blob */ + if (returnCode == TPM_SUCCESS) { + stream = b1EkBlob.blob.buffer; + stream_size = b1EkBlob.blob.size; + returnCode = TPM_EKBlobActivate_Load(&a1, &stream, &stream_size); + } + /* c. Compare H1 to A1 -> idDigest on mismatch return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(h1Digest, a1.idDigest); + if (returnCode != 0) { + printf("TPM_Process_ActivateIdentity: Error " + "comparing TPM_EK_TYPE_ACTIVATE idDigest\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If A1 -> pcrSelection is not NULL */ + /* i. Compute a composite hash C1 using the PCR selection A1 -> pcrSelection */ + /* ii. Compare C1 to A1 -> pcrInfo -> digestAtRelease and return TPM_WRONGPCRVAL on a + mismatch */ + /* e. If A1 -> pcrInfo specifies a locality ensure that the appropriate locality has been + asserted, return TPM_BAD_LOCALITY on error */ + if (returnCode == TPM_SUCCESS) { + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_PCRInfoShort_CheckDigest(&(a1.pcrInfo), + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* f. Set K1 to A1 -> symmetricKey */ + if (returnCode == TPM_SUCCESS) { + k1 = &(a1.sessionKey); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ActivateIdentity: 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; + /* 9. Return K1 */ + returnCode = TPM_SymmetricKey_Store(response, k1); + /* 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_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *idKeyHmacKey, /* owner HMAC key */ + id_key_auth_session_data, + outParamDigest, + idKeynonceOdd, + continueIdKeySession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueIdKeySession) && + idKeyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, idKeyAuthHandle); + } + /* 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(&blob); /* @1 */ + TPM_SymmetricKey_Delete(&symmetricKey); /* @2 */ + free(b1Blob); /* @3 */ + TPM_AsymCaContents_Delete(&b1AsymCaContents); /* @4 */ + TPM_EKBlob_Delete(&b1EkBlob); /* @5 */ + TPM_EKBlobActivate_Delete(&a1); /* @6 */ + return rcf; +} diff --git a/src/tpm12/tpm_identity.h b/src/tpm12/tpm_identity.h new file mode 100644 index 0000000..0f882d9 --- /dev/null +++ b/src/tpm12/tpm_identity.h @@ -0,0 +1,138 @@ +/********************************************************************************/ +/* */ +/* TPM Identity Handling */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_identity.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_IDENTITY_H +#define TPM_IDENTITY_H + +#include "tpm_global.h" + +/* + TPM_EK_BLOB +*/ + +void TPM_EKBlob_Init(TPM_EK_BLOB *tpm_ek_blob); +TPM_RESULT TPM_EKBlob_Load(TPM_EK_BLOB *tpm_ek_blob, + unsigned char **stream, + uint32_t *stream_size); +#if 0 +TPM_RESULT TPM_EKBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB *tpm_ek_blob); +#endif +void TPM_EKBlob_Delete(TPM_EK_BLOB *tpm_ek_blob); + +/* + TPM_EK_BLOB_ACTIVATE +*/ + +void TPM_EKBlobActivate_Init(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); +TPM_RESULT TPM_EKBlobActivate_Load(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate, + unsigned char **stream, + uint32_t *stream_size); +#if 0 +TPM_RESULT TPM_EKBlobActivate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); +#endif +void TPM_EKBlobActivate_Delete(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); + +/* + TPM_EK_BLOB_AUTH +*/ + +#if 0 +void TPM_EKBlobAuth_Init(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); +TPM_RESULT TPM_EKBlobAuth_Load(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_EKBlobAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); +void TPM_EKBlobAuth_Delete(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); +#endif + + +/* + TPM_IDENTITY_CONTENTS +*/ + +void TPM_IdentityContents_Init(TPM_IDENTITY_CONTENTS *tpm_identity_contents); +#if 0 +TPM_RESULT TPM_IdentityContents_Load(TPM_IDENTITY_CONTENTS *tpm_identity_contents, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_IdentityContents_Store(TPM_STORE_BUFFER *sbuffer, + TPM_IDENTITY_CONTENTS *tpm_identity_contents); +void TPM_IdentityContents_Delete(TPM_IDENTITY_CONTENTS *tpm_identity_contents); + +/* + TPM_ASYM_CA_CONTENTS +*/ + +void TPM_AsymCaContents_Init(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); +TPM_RESULT TPM_AsymCaContents_Load(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents, + unsigned char **stream, + uint32_t *stream_size); +#if 0 +TPM_RESULT TPM_AsymCaContents_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); +#endif +void TPM_AsymCaContents_Delete(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); + + +/* + Processing Functions +*/ + + +TPM_RESULT TPM_Process_MakeIdentity(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 TPM_Process_ActivateIdentity(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); + + +#endif diff --git a/src/tpm12/tpm_init.c b/src/tpm12/tpm_init.c new file mode 100644 index 0000000..3a66da5 --- /dev/null +++ b/src/tpm12/tpm_init.c @@ -0,0 +1,1144 @@ +/********************************************************************************/ +/* */ +/* TPM Initialization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_init.c 4623 2011-09-28 15:15:09Z 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 <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <time.h> + +#include "tpm_admin.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_session.h" +#include "tpm_startup.h" +#include "tpm_structures.h" +#include "tpm_ticks.h" +#include "tpm_transport.h" + + +#include "tpm_init.h" + +/* local prototypes */ + +static TPM_RESULT TPM_CheckTypes(void); + + +/* TPM_Init transitions the TPM from a power-off state to one where the TPM begins an initialization + process. TPM_Init could be the result of power being applied to the platform or a hard reset. + TPM_Init sets an internal flag to indicate that the TPM is undergoing initialization. The TPM + must complete initialization before it is operational. The completion of initialization requires + the receipt of the TPM_Startup command. + + This is different from the debug function TPM_Process_Init(), which initializes a TPM. + + The call tree for initialization is as follows: + + main() + TPM_MainInit() + TPM_IO_Init() - initializes the TPM I/O interface + TPM_Crypto_Init() - initializes cryptographic libraries + TPM_NVRAM_Init() - get NVRAM path once + TPM_LimitedSelfTest() - as per the specification + TPM_Global_Init() - initializes the TPM state + + Returns: 0 on success + + non-zero on a fatal error where the TPM should not continue. These are fatal errors + where the TPM just exits. It can't even enter shutdown. + + A self test error may cause one or all TPM's to enter shutdown, but is not fatal. +*/ + +TPM_RESULT TPM_MainInit(void) +{ + TPM_RESULT rc = 0; /* results for common code, fatal errors */ + uint32_t i; + TPM_RESULT testRc = 0; /* temporary place to hold common self tests failure before the tpm + state is created */ + tpm_state_t *tpm_state; /* TPM instance state */ + bool has_cached_state = false; + + tpm_state = NULL; /* freed @1 */ + /* preliminary check that platform specific sizes are correct */ + if (rc == 0) { + rc = TPM_CheckTypes(); + } + /* initialize the TPM to host interface */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM to host interface\n"); + rc = TPM_IO_Init(); + } + /* initialize cryptographic functions */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM crypto support\n"); + rc = TPM_Crypto_Init(); + } + /* initialize NVRAM static variables. This must be called before the global TPM state is + loaded */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM NVRAM\n"); + rc = TPM_NVRAM_Init(); + } + /* run the initial subset of self tests once */ + if (rc == 0) { + printf("TPM_MainInit: Run common limited self tests\n"); + /* an error is a fatal error, causes a shutdown of the TPM */ + testRc = TPM_LimitedSelfTestCommon(); + } + /* initialize the global structure for the TPM */ + for (i = 0 ; (rc == 0) && (i < TPMS_MAX) ; i++) { + printf("TPM_MainInit: Initializing global TPM %lu\n", (unsigned long)i); + /* Need to malloc and init a TPM state if this is the first time through or if the + state was saved in the array. Otherwise, the malloc'ed structure from the previous + time through the loop can be reused. */ + if ((rc == 0) && (tpm_state == NULL)) { + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&tpm_state, sizeof(tpm_state_t)); + } + /* initialize the global instance state */ + if (rc == 0) { + rc = TPM_Global_Init(tpm_state); /* freed @2 */ + } + } + if (rc == 0) { + has_cached_state = HasCachedState(TPMLIB_STATE_PERMANENT); + + /* record the TPM number in the state */ + tpm_state->tpm_number = i; + /* If the instance exists in NVRAM, it it initialized and saved in the tpm_instances[] + array. Restores TPM_PERMANENT_FLAGS and TPM_PERMANENT_DATA to in-memory + structures. */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + /* If there was no state for TPM 0 (instance 0 does not exist), initialize state for the + first time using TPM_Global_Init() above. It is created and set to default values. */ + if ((rc == TPM_RETRY) && (i == 0)) { + /* save the state for TPM 0 (first time through) */ + rc = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } +#ifdef TPM_VOLATILE_LOAD + /* if volatile state exists at startup, load it. This is used for fail-over restart. */ + if (rc == 0) { + rc = TPM_VolatileAll_NVLoad(tpm_state); + } +#endif /* TPM_VOLATILE_LOAD */ + /* libtpms: due to the SetState() API we have to write the permanent state back to + a file now */ + if (rc == 0 && has_cached_state) { + rc = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + /* if permanent state was loaded successfully (or stored successfully for TPM 0 the first + time) */ + if (rc == 0) { + printf("TPM_MainInit: Creating global TPM instance %lu\n", (unsigned long)i); + /* set the testState for the TPM based on the common selftest result */ + if (testRc != 0) { + /* a. When the TPM detects a failure during any self-test, it SHOULD delete values + preserved by TPM_SaveState. */ + TPM_SaveState_NVDelete(tpm_state, + FALSE); /* ignore error if the state does not exist */ + printf(" TPM_MainInit: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + /* save state in array */ + tpm_instances[i] = tpm_state; + tpm_state = NULL; /* flag that the malloc'ed structure was used. It should not be + freed, and a new instance is needed the next time through the + loop */ + } + /* If there was the non-fatal error TPM_RETRY, the instance does not exist. If instance > 0 + does not exist, the array entry is set to NULL. Continue */ + else if (rc == TPM_RETRY) { + printf("TPM_MainInit: Not Creating global TPM %lu\n", (unsigned long)i); + tpm_instances[i] = NULL; /* flag that the instance does not exist */ + rc = 0; /* Instance does not exist, not fatal error */ + } + } + /* run individual self test on a TPM */ + for (i = 0 ; + (rc == 0) && (i < TPMS_MAX) && (tpm_instances[i] != NULL) && + (tpm_instances[i]->testState != TPM_TEST_STATE_FAILURE) ; /* don't continue if already + error */ + i++) { + printf("TPM_MainInit: Run limited self tests on TPM %lu\n", (unsigned long)i); + testRc = TPM_LimitedSelfTestTPM(tpm_instances[i]); + if (testRc != 0) { + /* a. When the TPM detects a failure during any self-test, it SHOULD delete values + preserved by TPM_SaveState. */ + TPM_SaveState_NVDelete(tpm_state, + FALSE); /* ignore error if the state does not exist */ + } + } + /* the _Delete(), free() clean up if the last created instance was not required */ + TPM_Global_Delete(tpm_state); /* @2 */ + free(tpm_state); /* @1 */ + return rc; +} + +/* TPM_CheckTypes() checks that the assumed TPM types are correct for the platform + */ + +static TPM_RESULT TPM_CheckTypes(void) +{ + TPM_RESULT rc = 0; /* fatal errors */ + + /* These should be removed at compile time */ + if (rc == 0) { + if (sizeof(uint16_t) != 2) { + printf("TPM_CheckTypes: Error (fatal), uint16_t size %lu not supported\n", + (unsigned long)sizeof(uint16_t)); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (sizeof(uint32_t) != 4) { + printf("TPM_CheckTypes: Error (fatal), uint32_t size %lu not supported\n", + (unsigned long)sizeof(uint32_t)); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if ((sizeof(time_t) != 4) && /* for 32-bit machines */ + (sizeof(time_t) != 8)) { /* for 64-bit machines */ + printf("TPM_CheckTypes: Error (fatal), time_t size %lu not supported\n", + (unsigned long)sizeof(time_t)); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + TPM_STANY_FLAGS +*/ + +/* TPM_StanyFlags_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StanyFlags_Init(TPM_STANY_FLAGS *tpm_stany_flags) +{ + printf(" TPM_StanyFlags_Init:\n"); + tpm_stany_flags->postInitialise = TRUE; + tpm_stany_flags->localityModifier = 0; + tpm_stany_flags->transportExclusive = 0; + tpm_stany_flags->TOSPresent = FALSE; + /* NOTE added */ + tpm_stany_flags->stateSaved = FALSE; + return; +} + +/* TPM_StanyFlags_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StanyFlags_Init() +*/ + +TPM_RESULT TPM_StanyFlags_Load(TPM_STANY_FLAGS *tpm_stany_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyFlags_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STANY_FLAGS, stream, stream_size); + } + /* load postInitialise*/ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->postInitialise), stream, stream_size); + } + /* load localityModifier */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stany_flags->localityModifier), stream, stream_size); + } + /* load transportExclusive */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stany_flags->transportExclusive), stream, stream_size); + } + /* load TOSPresent */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->TOSPresent), stream, stream_size); + } + /* load stateSaved */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->stateSaved), stream, stream_size); + } + return rc; +} + +/* TPM_StanyFlags_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StanyFlags_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_FLAGS *tpm_stany_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyFlags_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STANY_FLAGS); + } + /* store postInitialise*/ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->postInitialise), sizeof(TPM_BOOL)); + } + /* store localityModifier */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stany_flags->localityModifier); + } + /* store transportExclusive */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stany_flags->transportExclusive); + } + /* store TOSPresent */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->TOSPresent), sizeof(TPM_BOOL)); + } + /* store stateSaved */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->stateSaved), sizeof(TPM_BOOL)); + } + return rc; +} + +/* + TPM_STCLEAR_FLAGS +*/ + +/* TPM_StclearFlags_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StclearFlags_Init(TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + printf(" TPM_StclearFlags_Init:\n"); + /* tpm_stclear_flags->deactivated; no default state */ + tpm_stclear_flags->disableForceClear = FALSE; + tpm_stclear_flags->physicalPresence = FALSE; + tpm_stclear_flags->physicalPresenceLock = FALSE; + tpm_stclear_flags->bGlobalLock = FALSE; + return; +} + +/* TPM_StclearFlags_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StclearFlags_Init() +*/ + +TPM_RESULT TPM_StclearFlags_Load(TPM_STCLEAR_FLAGS *tpm_stclear_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearFlags_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STCLEAR_FLAGS, stream, stream_size); + } + /* load deactivated */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->deactivated), stream, stream_size); + } + /* load disableForceClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->disableForceClear), stream, stream_size); + } + /* load physicalPresence */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->physicalPresence), stream, stream_size); + } + /* load physicalPresenceLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->physicalPresenceLock), stream, stream_size); + } + /* load bGlobalLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->bGlobalLock), stream, stream_size); + } + return rc; +} + +/* TPM_StclearFlags_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StclearFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearFlags_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_FLAGS); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->deactivated), + sizeof(TPM_BOOL)); + } + /* store disableForceClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->disableForceClear), + sizeof(TPM_BOOL)); + } + /* store physicalPresence */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->physicalPresence), + sizeof(TPM_BOOL)); + } + /* store physicalPresenceLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->physicalPresenceLock), + sizeof(TPM_BOOL)); + } + /* store bGlobalLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->bGlobalLock), + sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_StclearFlags_StoreBitmap() serializes TPM_STCLEAR_FLAGS structure into a bit map + + */ + +TPM_RESULT TPM_StclearFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + printf(" TPM_StclearFlags_StoreBitmap:\n"); + *tpm_bitmap = 0; + /* store deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->deactivated, &pos); + } + /* store disableForceClear */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->disableForceClear, &pos); + } + /* store physicalPresence */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->physicalPresence, &pos); + } + /* store physicalPresenceLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->physicalPresenceLock, &pos); + } + /* store bGlobalLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->bGlobalLock, &pos); + } + return rc; +} + +/* + TPM_STANY_DATA +*/ + +/* TPM_StanyData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 +*/ + +TPM_RESULT TPM_StanyData_Init(TPM_STANY_DATA *tpm_stany_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Init:\n"); + if (rc == 0) { + /* The tpm_stany_data->currentTicks holds the time of day at initialization. Both nonce + generation and current time of day can return an error */ + TPM_CurrentTicks_Init(&(tpm_stany_data->currentTicks)); + rc = TPM_CurrentTicks_Start(&(tpm_stany_data->currentTicks)); + } + return rc; +} + +/* TPM_StanyData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StanyData_Init() + After use, call TPM_StanyData_Delete() to free memory +*/ + +TPM_RESULT TPM_StanyData_Load(TPM_STANY_DATA *tpm_stany_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Load:\n"); + tpm_stany_data = tpm_stany_data; + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STANY_DATA, stream, stream_size); + } + /* load currentTicks */ + if (rc == 0) { + rc = TPM_CurrentTicks_LoadAll(&(tpm_stany_data->currentTicks), stream, stream_size); + } + return rc; +} + +/* TPM_StanyData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StanyData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_DATA *tpm_stany_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Store:\n"); + tpm_stany_data = tpm_stany_data; + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STANY_DATA); + } + /* store currentTicks*/ + if (rc == 0) { + rc = TPM_CurrentTicks_StoreAll(sbuffer, &(tpm_stany_data->currentTicks)); + } + return rc; +} + +/* TPM_StanyData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + set members back to default values + The object itself is not freed +*/ + +void TPM_StanyData_Delete(TPM_STANY_DATA *tpm_stany_data) +{ + printf(" TPM_StanyData_Delete:\n"); + /* nothing to free */ + tpm_stany_data = tpm_stany_data; + return; +} + +/* + TPM_STCLEAR_DATA +*/ + +/* TPM_StclearData_Init() + + If pcrInit is TRUE, resets the PCR's + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StclearData_Init(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit) +{ + printf(" TPM_StclearData_Init:\n"); + TPM_Nonce_Init(tpm_stclear_data->contextNonceKey); + tpm_stclear_data->countID = TPM_COUNT_ID_NULL; /* NULL value - unselected counter */ + tpm_stclear_data->ownerReference = TPM_KH_OWNER; + tpm_stclear_data->disableResetLock = FALSE; + /* initialize PCR's */ + if (pcrInit) { + printf("TPM_StclearData_Init: Initializing PCR's\n"); + TPM_PCRs_Init(tpm_stclear_data->PCRS, pcrAttrib); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + tpm_stclear_data->deferredPhysicalPresence = 0; +#endif + tpm_stclear_data->authFailCount = 0; + tpm_stclear_data->authFailTime = 0; + /* initialize authorization, transport, DAA sessions, and saved sessions */ + TPM_StclearData_SessionInit(tpm_stclear_data); + TPM_Digest_Init(tpm_stclear_data->auditDigest); + TPM_Sbuffer_Init(&(tpm_stclear_data->ordinalResponse)); + return; +} + +/* TPM_StclearData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StclearData_Init() + After use, call TPM_StclearData_Delete() to free memory +*/ + +TPM_RESULT TPM_StclearData_Load(TPM_STCLEAR_DATA *tpm_stclear_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_PCR_ATTRIBUTES *pcrAttrib) +{ + TPM_RESULT rc = 0; + TPM_STRUCTURE_TAG tag = 0; + + printf(" TPM_StclearData_Load:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(&tag, stream, stream_size); + } + /* check tag */ + if (rc == 0) { + printf(" TPM_StclearData_Load: stream version %04hx\n", tag); + switch (tag) { + case TPM_TAG_STCLEAR_DATA: + case TPM_TAG_STCLEAR_DATA_V2: + break; + default: + printf("TPM_StclearData_Load: Error (fatal), version %04x unsupported\n", tag); + rc = TPM_FAIL; + break; + } + } + /* load contextNonceKey */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_stclear_data->contextNonceKey, stream, stream_size); + } + /* load countID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->countID), stream, stream_size); + } + /* load ownerReference */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->ownerReference), stream, stream_size); + } + /* load disableResetLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_data->disableResetLock), stream, stream_size); + } + /* load PCR's */ + if (rc == 0) { + rc = TPM_PCRs_Load(tpm_stclear_data->PCRS, pcrAttrib, stream, stream_size); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* load deferredPhysicalPresence */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->deferredPhysicalPresence), stream, stream_size); + } +#endif + /* load authFailCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->authFailCount), stream, stream_size); + } + /* load authFailTime */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->authFailTime), stream, stream_size); + } + /* load authorization sessions */ + if (rc == 0) { + rc = TPM_AuthSessions_Load(tpm_stclear_data->authSessions, stream, stream_size); + } + /* load transport sessions */ + if (rc == 0) { + rc = TPM_TransportSessions_Load(tpm_stclear_data->transSessions, stream, stream_size); + } + /* load DAA sessions */ + if (rc == 0) { + rc = TPM_DaaSessions_Load(tpm_stclear_data->daaSessions, stream, stream_size); + } + /* load contextNonceSession */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_stclear_data->contextNonceSession, stream, stream_size); + } + /* load contextCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->contextCount), stream, stream_size); + } + /* load contextList */ + if (rc == 0) { + rc = TPM_ContextList_Load(tpm_stclear_data->contextList, stream, stream_size); + } + /* load auditDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_stclear_data->auditDigest, stream, stream_size); + TPM_PrintFour(" TPM_StclearData_Load: auditDigest", tpm_stclear_data->auditDigest); + } + /* no need to store and load ordinalResponse */ + if (tag == TPM_TAG_STCLEAR_DATA) { + /* but it's there for some versions */ + if (rc == 0) { + TPM_STORE_BUFFER ordinalResponse; + TPM_Sbuffer_Init(&ordinalResponse); + rc = TPM_Sbuffer_Load(&ordinalResponse, stream, stream_size); + TPM_Sbuffer_Delete(&ordinalResponse); + } + if (rc == 0) { + uint32_t responseCount; + rc = TPM_Load32(&responseCount, stream, stream_size); + } + } + return rc; +} + +/* TPM_StclearData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StclearData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_DATA_V2); + } + /* store contextNonceKey */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_stclear_data->contextNonceKey); + } + /* store countID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->countID); + } + /* store ownerReference */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->ownerReference); + } + /* store disableResetLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_data->disableResetLock), + sizeof(TPM_BOOL)); + } + /* store PCR's */ + if (rc == 0) { + rc = TPM_PCRs_Store(sbuffer, tpm_stclear_data->PCRS, pcrAttrib); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store deferredPhysicalPresence */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->deferredPhysicalPresence); + } +#endif + /* store authFailCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->authFailCount); + } + /* store authFailTime */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->authFailTime); + } + /* store authorization sessions */ + if (rc == 0) { + rc = TPM_AuthSessions_Store(sbuffer, tpm_stclear_data->authSessions); + } + /* store transport sessions */ + if (rc == 0) { + rc = TPM_TransportSessions_Store(sbuffer, tpm_stclear_data->transSessions); + } + /* store DAA sessions */ + if (rc == 0) { + rc = TPM_DaaSessions_Store(sbuffer, tpm_stclear_data->daaSessions); + } + /* store contextNonceSession */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_stclear_data->contextNonceSession); + } + /* store contextCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->contextCount); + } + /* store contextList */ + if (rc == 0) { + rc = TPM_ContextList_Store(sbuffer, tpm_stclear_data->contextList); + } + /* store auditDigest */ + if (rc == 0) { + TPM_PrintFour(" TPM_StclearData_Store: auditDigest", tpm_stclear_data->auditDigest); + rc = TPM_Digest_Store(sbuffer, tpm_stclear_data->auditDigest); + } + /* no need to store and load ordinalResponse */ + return rc; +} + +/* TPM_StclearData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_StclearData_Init to set members back to default values + The object itself is not freed +*/ + +/* TPM_StclearData_Delete() frees any memory associated with TPM_STCLEAR_DATA, and then + reinitializes the structure. + + If pcrInit is TRUE, the PCR's are initialized. +*/ + +void TPM_StclearData_Delete(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit) +{ + printf(" TPM_StclearData_Delete:\n"); + if (tpm_stclear_data != NULL) { + TPM_StclearData_SessionDelete(tpm_stclear_data);/* authorization, transport, and DAA + sessions */ + TPM_Sbuffer_Delete(&(tpm_stclear_data->ordinalResponse)); + TPM_StclearData_Init(tpm_stclear_data, pcrAttrib, pcrInit); + } + return; +} + +/* TPM_StclearData_SessionInit() initializes the structure members associated with authorization, + transport, and DAA sessions. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_SessionInit(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_SessionInit:\n"); + /* active sessions */ + TPM_AuthSessions_Init(tpm_stclear_data->authSessions); + TPM_TransportSessions_Init(tpm_stclear_data->transSessions); + TPM_DaaSessions_Init(tpm_stclear_data->daaSessions); + /* saved sessions */ + TPM_Nonce_Init(tpm_stclear_data->contextNonceSession); + tpm_stclear_data->contextCount = 0; + TPM_ContextList_Init(tpm_stclear_data->contextList); + return; +} + +/* TPM_StclearData_SessionDelete() deletes the structure members associated with authorization, + transport, and DAA sessions. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_SessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_SessionDelete:\n"); + /* active and saved authorization sessions, the authSessions table and the 3 contextList + entries */ + TPM_StclearData_AuthSessionDelete(tpm_stclear_data); + /* loaded transport sessions */ + TPM_TransportSessions_Delete(tpm_stclear_data->transSessions); + /* loaded DAA sessions */ + TPM_DaaSessions_Delete(tpm_stclear_data->daaSessions); + return; +} + +/* TPM_StclearData_AuthSessionDelete() deletes the structure members associated with authorization + sessions. It clears the authSessions table and the 3 contextList members. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_AuthSessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_AuthSessionDelete:\n"); + /* active sessions */ + TPM_AuthSessions_Delete(tpm_stclear_data->authSessions); + /* saved sessions */ + TPM_Nonce_Init(tpm_stclear_data->contextNonceSession); + tpm_stclear_data->contextCount = 0; + TPM_ContextList_Init(tpm_stclear_data->contextList); + return; +} + +/* + TPM_InitCmd() executes the actions of the TPM_Init 'ordinal' +*/ + +TPM_RESULT TPM_InitCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + uint32_t tpm_number; + + printf(" TPM_Init:\n"); + /* Release all resources for the TPM and reinitialize */ + if (rc == TPM_SUCCESS) { + tpm_number = tpm_state->tpm_number; /* save the TPM value */ + TPM_Global_Delete(tpm_state); /* delete all the state */ + rc = TPM_Global_Init(tpm_state); /* re-allocate the state */ + } + /* Reload non-volatile memory */ + if (rc == TPM_SUCCESS) { + tpm_state->tpm_number = tpm_number; /* restore the TPM number */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_PermanentAll_NVLoad(tpm_state); /* reload the state */ + if (rc == TPM_RETRY) { + printf("TPM_Init: Error (fatal), non-existent instance\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + TPM_Handle_GenerateHandle() is a utility function that returns an unused handle. + + It's really not an initialization function, but as the handle arrays are typically in + TPM_STCLEAR_DATA, it's a reasonable home. + + If 'tpm_handle' is non-zero, it is the first value tried. If 'keepHandle' is TRUE, it is the only + value tried. + + If 'tpm_handle' is zero, a random value is assigned. If 'keepHandle' is TRUE, an error returned, + as zero is an illegal handle value. + + If 'isKeyHandle' is TRUE, special checking is performed to avoid reserved values. + + 'getEntryFunction' is a function callback to check whether the handle has already been assigned to + an entry in the appropriate handle list. +*/ + +TPM_RESULT TPM_Handle_GenerateHandle(TPM_HANDLE *tpm_handle, + void *tpm_handle_entries, + TPM_BOOL keepHandle, + TPM_BOOL isKeyHandle, + TPM_GETENTRY_FUNCTION_T getEntryFunction) +{ + TPM_RESULT rc = 0; + TPM_RESULT getRc = 0; + unsigned int timeout; /* collision timeout */ + void *used_handle_entry; /* place holder for discarded entry */ + TPM_BOOL done; + + printf(" TPM_Handle_GenerateHandle: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* if the input value must be used */ + if (keepHandle) { + /* 0 is illegal and cannot be kept */ + if (rc == 0) { + if (*tpm_handle == 0) { + printf("TPM_Handle_GenerateHandle: Error, cannot keep handle 0\n"); + rc = TPM_BAD_HANDLE; + } + } + /* key handles beginning with 0x40 are reserved special values */ + if (rc == 0) { + if (isKeyHandle) { + if ((*tpm_handle & 0xff000000) == 0x40000000) { + printf("TPM_Handle_GenerateHandle: Error, cannot keep reserved key handle\n"); + rc = TPM_BAD_HANDLE; + } + } + } + /* check if the handle is already used */ + if (rc == 0) { + getRc = getEntryFunction(&used_handle_entry, /* discarded entry */ + tpm_handle_entries, /* handle array */ + *tpm_handle); /* search for handle */ + /* success mean the handle has already been assigned */ + if (getRc == 0) { + printf("TPM_Handle_GenerateHandle: Error handle already in use\n"); + rc = TPM_BAD_HANDLE; + } + } + } + /* input value is recommended but not required */ + else { + /* implement a crude timeout in case the random number generator fails and there are too + many collisions */ + for (done = FALSE, timeout = 0 ; (rc == 0) && !done && (timeout < 1000) ; timeout++) { + /* If no handle has been assigned, try a random value. If a handle has been assigned, + try it first */ + if (rc == 0) { + if (*tpm_handle == 0) { + rc = TPM_Random((BYTE *)tpm_handle, sizeof(uint32_t)); + } + } + /* if the random value is 0, reject it immediately */ + if (rc == 0) { + if (*tpm_handle == 0) { + printf(" TPM_Handle_GenerateHandle: Random value 0 rejected\n"); + continue; + } + } + /* if the value is a reserved key handle, reject it immediately */ + if (rc == 0) { + if (isKeyHandle) { + if ((*tpm_handle & 0xff000000) == 0x40000000) { + printf(" TPM_Handle_GenerateHandle: Random value %08x rejected\n", + *tpm_handle); + *tpm_handle = 0; /* ignore the assigned value */ + continue; + } + } + } + /* test if the handle has already been used */ + if (rc == 0) { + getRc = getEntryFunction(&used_handle_entry, /* discarded entry */ + tpm_handle_entries, /* handle array */ + *tpm_handle); /* search for handle */ + if (getRc != 0) { /* not found, done */ + printf(" TPM_Handle_GenerateHandle: Assigned Handle %08x\n", + *tpm_handle); + done = TRUE; + } + else { /* found, try again */ + *tpm_handle = 0; /* ignore the assigned value */ + printf(" TPM_Handle_GenerateHandle: Handle %08x already used\n", + *tpm_handle); + } + } + } + if (!done) { + printf("TPM_Handle_GenerateHandle: Error (fatal), random number generator failed\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + Processing Functions +*/ + +/* TPM_Init + + This ordinal should not be implemented, since it allows software to imitate a reboot. That would + be a major security hole, since the PCR's are reset. + + It is only here for regression tests. +*/ + +TPM_RESULT TPM_Process_Init(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 */ + + printf("TPM_Process_Init: Ordinal Entry\n"); + ordinal = ordinal; /* not used */ + command = command; /* not used */ + transportInternal = transportInternal; /* not used */ + /* check state */ + /* NOTE: Allow at any time. */ + /* + get inputs + */ + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Init: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { +#ifdef TPM_TEST + returnCode = TPM_InitCmd(tpm_state); +#else + tpm_state = tpm_state; /* to quiet the compiler */ + printf("TPM_Process_Init: Error, bad ordinal\n"); + returnCode = TPM_BAD_ORDINAL; +#endif + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Init: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + return rcf; +} + diff --git a/src/tpm12/tpm_init.h b/src/tpm12/tpm_init.h new file mode 100644 index 0000000..276e537 --- /dev/null +++ b/src/tpm12/tpm_init.h @@ -0,0 +1,136 @@ +/********************************************************************************/ +/* */ +/* TPM Initialization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_init.h 4403 2011-02-08 18:28:22Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_INIT_H +#define TPM_INIT_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* Power up initialization */ +TPM_RESULT TPM_MainInit(void); + +/* + TPM_STANY_FLAGS +*/ + +void TPM_StanyFlags_Init(TPM_STANY_FLAGS *tpm_stany_flags); + +TPM_RESULT TPM_StanyFlags_Load(TPM_STANY_FLAGS *tpm_stany_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StanyFlags_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_FLAGS *tpm_stany_flags); + +/* + TPM_STCLEAR_FLAGS +*/ + +void TPM_StclearFlags_Init(TPM_STCLEAR_FLAGS *tpm_stclear_flags); +TPM_RESULT TPM_StclearFlags_Load(TPM_STCLEAR_FLAGS *tpm_stclear_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StclearFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags); +TPM_RESULT TPM_StclearFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags); +/* + TPM_STANY_DATA +*/ + +TPM_RESULT TPM_StanyData_Init(TPM_STANY_DATA *tpm_stany_data); +TPM_RESULT TPM_StanyData_Load(TPM_STANY_DATA *tpm_stany_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StanyData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_DATA *tpm_stany_data); +void TPM_StanyData_Delete(TPM_STANY_DATA *tpm_stany_data); + +/* + TPM_STCLEAR_DATA +*/ + +void TPM_StclearData_Init(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit); +TPM_RESULT TPM_StclearData_Load(TPM_STCLEAR_DATA *tpm_stclear_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_PCR_ATTRIBUTES *pcrAttrib); +TPM_RESULT TPM_StclearData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib); +void TPM_StclearData_Delete(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit); + +void TPM_StclearData_SessionInit(TPM_STCLEAR_DATA *tpm_stclear_data); +void TPM_StclearData_SessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data); +void TPM_StclearData_AuthSessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data); + +/* Actions */ + +TPM_RESULT TPM_InitCmd(tpm_state_t *tpm_state); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_Init(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); + +/* generic function prototype for a handle array getEntry callback function */ + +typedef TPM_RESULT (*TPM_GETENTRY_FUNCTION_T )(void **entry, + void *entries, + TPM_HANDLE handle); + +TPM_RESULT TPM_Handle_GenerateHandle(TPM_HANDLE *tpm_handle, + void *tpm_handle_entries, + TPM_BOOL keepHandle, + TPM_BOOL isKeyHandle, + TPM_GETENTRY_FUNCTION_T getEntryFunction); + +#endif diff --git a/src/tpm12/tpm_io.h b/src/tpm12/tpm_io.h new file mode 100644 index 0000000..055b0ba --- /dev/null +++ b/src/tpm12/tpm_io.h @@ -0,0 +1,71 @@ +/********************************************************************************/ +/* */ +/* TPM Host IO */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_io.h 4211 2010-11-22 21:07:24Z 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. */ +/********************************************************************************/ + +#ifndef TPM_IO_H +#define TPM_IO_H + +#include "tpm_types.h" + +/* non-portable structure to pass around IO file descriptor */ + +typedef struct TPM_CONNECTION_FD { +#ifdef TPM_POSIX + int fd; /* for socket, just an int */ +#endif +} TPM_CONNECTION_FD; + + +TPM_RESULT TPM_IO_IsNotifyAvailable(TPM_BOOL *isAvailable); +TPM_RESULT TPM_IO_Connect(TPM_CONNECTION_FD *connection_fd, + void *mainLoopArgs); +TPM_RESULT TPM_IO_Read(TPM_CONNECTION_FD *connection_fd, + unsigned char *buffer, + uint32_t *paramSize, + size_t buffer_size, + void *mainLoopArgs); +TPM_RESULT TPM_IO_Write(TPM_CONNECTION_FD *connection_fd, + const unsigned char *buffer, + size_t buffer_length); +TPM_RESULT TPM_IO_Disconnect(TPM_CONNECTION_FD *connection_fd); + +/* function for notifying listener(s) about PCRExtend events */ +TPM_RESULT TPM_IO_ClientSendNotification(const void *buf, size_t count); + + +#endif diff --git a/src/tpm12/tpm_key.c b/src/tpm12/tpm_key.c new file mode 100644 index 0000000..6fce495 --- /dev/null +++ b/src/tpm12/tpm_key.c @@ -0,0 +1,5529 @@ +/********************************************************************************/ +/* */ +/* Key Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_key.c 4655 2011-12-21 21:03:15Z 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_auth.h" +#include "tpm_commands.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_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvram.h" +#include "tpm_owner.h" +#include "tpm_pcr.h" +#include "tpm_sizedbuffer.h" +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_startup.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_ver.h" + +#include "tpm_key.h" + +/* The default RSA exponent */ +unsigned char tpm_default_rsa_exponent[] = {0x01, 0x00, 0x01}; + +/* local prototypes */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12); + +/* + TPM_KEY, TPM_KEY12 + + These functions generally handle either a TPM_KEY or TPM_KEY12. Where structure members differ, + the function checks the version or tag and adapts the processing to the structure type. This + handling is opaque to the caller. +*/ + + +/* TPM_Key_Init initializes a key structure. The default is TPM_KEY. Typically, a TPM_Key_Set() or + TPM_Key_Load() will adjust to TPM_KEY or TPM_KEY12 */ + +void TPM_Key_Init(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_Init:\n"); + TPM_StructVer_Init(&(tpm_key->ver)); + tpm_key->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_key->keyFlags = 0; + tpm_key->authDataUsage = 0; + TPM_KeyParms_Init(&(tpm_key->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_key->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_key->pubKey)); + TPM_SizedBuffer_Init(&(tpm_key->encData)); + tpm_key->tpm_pcr_info = NULL; + tpm_key->tpm_pcr_info_long = NULL; + tpm_key->tpm_store_asymkey = NULL; + tpm_key->tpm_migrate_asymkey = NULL; + return; +} + +/* TPM_Key_InitTag12() alters the tag and fill from TPM_KEY to TPM_KEY12 */ + +void TPM_Key_InitTag12(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_InitTag12:\n"); + ((TPM_KEY12 *)tpm_key)->tag = TPM_TAG_KEY12; + ((TPM_KEY12 *)tpm_key)->fill = 0x0000; + return; +} + +/* TPM_Key_Set() sets a TPM_KEY structure to the specified values. + + The tpm_pcr_info digestAtCreation is calculated. + + It serializes the tpm_pcr_info or tpm_pcr_info_long cache to pcrInfo. One or the other may be + specified, but not both. The tag/version is set correctly. + + If the parent_key is NULL, encData is set to the clear text serialization of the + tpm_store_asymkey member. + + If parent_key is not NULL, encData is not set yet, since further processing may be done before + encryption. + + Must call TPM_Key_Delete() to free + */ + +TPM_RESULT TPM_Key_Set(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* points to the TPM PCR array */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* must copy */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long, /* must copy */ + uint32_t keyLength, /* public key length in bytes */ + BYTE* publicKey, /* public key byte array */ + TPM_STORE_ASYMKEY *tpm_store_asymkey, /* cache TPM_STORE_ASYMKEY */ + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) /* cache TPM_MIGRATE_ASYMKEY */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + + printf(" TPM_Key_Set:\n"); + TPM_Sbuffer_Init(&sbuffer); + /* version must be TPM_KEY or TPM_KEY12 */ + if (rc == 0) { + if ((ver != 1) && (ver != 2)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY version %d is not 1 or 2\n", ver); + rc = TPM_FAIL; /* should never occur */ + } + } + /* either tpm_pcr_info != NULL for TPM_KEY or tpm_pcr_info_long != NULL for TPM_KEY12, but not + both */ + if (rc == 0) { + if ((ver == 1) && (tpm_pcr_info_long != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY and TPM_PCR_INFO_LONG both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + if ((ver == 2) && (tpm_pcr_info != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY12 and TPM_PCR_INFO both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + TPM_Key_Init(tpm_key); + if (ver == 2) { + TPM_Key_InitTag12(tpm_key); /* change tag to TPM_KEY12 */ + } + tpm_key->keyUsage = keyUsage; + tpm_key->keyFlags = keyFlags; + tpm_key->authDataUsage = authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key->algorithmParms), /* freed by caller */ + tpm_key_parms); + } + /* The pcrInfo serialization is deferred, since PCR data is be altered after the initial + 'set'. */ + if (rc == 0) { + /* generate the TPM_PCR_INFO member cache, directly copying from the tpm_pcr_info */ + if (tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key->tpm_pcr_info), tpm_pcr_info); + } + /* generate the TPM_PCR_INFO_LONG member cache, directly copying from the + tpm_pcr_info_long */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key->tpm_pcr_info_long), + tpm_pcr_info_long); + } + } + if (rc == 0) { + /* if there are PCR's specified, set the digestAtCreation */ + if (tpm_pcr_info != NULL) { + rc = TPM_PCRInfo_SetDigestAtCreation(tpm_key->tpm_pcr_info, tpm_pcrs); + } + /* if there are PCR's specified, set the localityAtCreation, digestAtCreation */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + if (rc == 0) { + rc = TPM_Locality_Set(&(tpm_key->tpm_pcr_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + rc = TPM_PCRInfoLong_SetDigestAtCreation(tpm_key->tpm_pcr_info_long, tpm_pcrs); + } + } + } + /* set TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->pubKey), + keyLength, /* in bytes */ + publicKey); + } + if (rc == 0) { + if (tpm_store_asymkey == NULL) { + printf("TPM_Key_Set: Error (fatal), No TPM_STORE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* sanity check, currently no need to set TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + if (tpm_migrate_asymkey != NULL) { + printf("TPM_Key_Set: Error (fatal), TPM_MIGRATE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* root key, no parent, just serialize the TPM_STORE_ASYMKEY structure */ + if (parent_key == NULL) { + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(&(tpm_key->encData), &sbuffer); + } + } + } + if (rc == 0) { + tpm_key->tpm_store_asymkey = tpm_store_asymkey; /* cache TPM_STORE_ASYMKEY */ + tpm_key->tpm_migrate_asymkey = tpm_migrate_asymkey; /* cache TPM_MIGRATE_ASYMKEY */ + } + /* Generate the TPM_STORE_ASYMKEY -> pubDataDigest. Serializes pcrInfo as a side effect. */ + if (rc == 0) { + rc = TPM_Key_GeneratePubDataDigest(tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_Copy() copies the source TPM_KEY to the destination. + + The destination should be initialized before the call. +*/ + +TPM_RESULT TPM_Key_Copy(TPM_KEY *tpm_key_dest, + TPM_KEY *tpm_key_src, + TPM_BOOL copyEncData) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + TPM_StructVer_Copy(&(tpm_key_dest->ver), &(tpm_key_src->ver)); /* works for TPM_KEY12 + also */ + tpm_key_dest->keyUsage = tpm_key_src->keyUsage; + tpm_key_dest->keyFlags = tpm_key_src->keyFlags; + tpm_key_dest->authDataUsage = tpm_key_src->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key_dest->algorithmParms), &(tpm_key_src->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pcrInfo), &(tpm_key_src->pcrInfo)); + } + /* copy TPM_PCR_INFO cache */ + if (rc == 0) { + if (tpm_key_src->tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key_dest->tpm_pcr_info), + tpm_key_src->tpm_pcr_info); + } + else if (tpm_key_src->tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key_dest->tpm_pcr_info_long), + tpm_key_src->tpm_pcr_info_long); + } + } + /* copy pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pubKey), &(tpm_key_src->pubKey)); + } + /* copy encData */ + if (rc == 0) { + if (copyEncData) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->encData), &(tpm_key_src->encData)); + } + } + return rc; +} + +/* TPM_Key_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + After use, call TPM_Key_Delete() to free memory +*/ + + +TPM_RESULT TPM_Key_Load(TPM_KEY *tpm_key, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Load:\n"); + /* load public data, and create PCR cache */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, FALSE, stream, stream_size); + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->encData), stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadClear() load a serialized key where the TPM_STORE_ASYMKEY structure is serialized in + clear text. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + This function is used to load internal keys (e.g. EK, SRK, owner evict keys) or keys saved as + part of a save state. +*/ + +TPM_RESULT TPM_Key_LoadClear(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + uint32_t storeAsymkeySize; + + printf(" TPM_Key_LoadClear:\n"); + /* load public data */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, isEK, stream, stream_size); + } + /* load TPM_STORE_ASYMKEY size */ + if (rc == 0) { + rc = TPM_Load32(&storeAsymkeySize, stream, stream_size); + } + /* The size might be 0 for an uninitialized internal key. That case is not an error. */ + if ((rc == 0) && (storeAsymkeySize > 0)) { + rc = TPM_Key_LoadStoreAsymKey(tpm_key, isEK, stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadPubData() deserializes a TPM_KEY or TPM_KEY12 structure, excluding encData, to + 'tpm_key'. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + If the pcrInfo stream is empty, the caches remain NULL. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_Key_Delete() to free memory +*/ + +TPM_RESULT TPM_Key_LoadPubData(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_LoadPubData:\n"); + /* peek at the first byte */ + if (rc == 0) { + /* TPM_KEY[0] is major (non zero) */ + if ((*stream)[0] != 0) { + /* load ver */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_key->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); + } + } + else { + /* TPM_KEY12 is tag (zero) */ + /* load tag */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->tag), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->fill), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + } + } + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_key->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_key->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_key->algorithmParms), stream, stream_size); + } + /* load PCRInfo */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from PCRInfo stream. If the stream is empty, a NULL is + returned. + */ + if ((rc == 0) && !isEK) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_key->tpm_pcr_info), + &(tpm_key->pcrInfo)); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromBuffer(&(tpm_key->tpm_pcr_info_long), + &(tpm_key->pcrInfo)); + } + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Key_StorePubData() serializes a TPM_KEY or TPM_KEY12 structure, excluding encData, appending + results to 'sbuffer'. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StorePubData(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubData:\n"); + + if (rc == 0) { + /* store ver */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_StructVer_Store(sbuffer, &(tpm_key->ver)); + } + else { /* TPM_KEY12 */ + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY12); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, 0x0000); + } + } + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_key->authDataUsage), sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_key->algorithmParms)); + } + /* store pcrInfo */ + if ((rc == 0) && !isEK) { + /* copy cache to pcrInfo */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { /* TPM_KEY12 */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info_long, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy pcrInfo to sbuffer */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pcrInfo)); + } + /* store pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pubKey)); + } + return rc; +} + +/* TPM_Key_Store() serializes a TPM_KEY structure, appending results to 'sbuffer' + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Store:\n"); + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, FALSE, tpm_key); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->encData)); + } + return rc; +} + +/* TPM_Key_StoreClear() serializes a TPM_KEY structure, appending results to 'sbuffer' + + TPM_Key_StoreClear() serializes the tpm_store_asymkey member as cleartext. It is used for keys + such as the SRK, which never leave the TPM. It is also used for saving state, where the entire + blob is encrypted. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StoreClear(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, /* key being stored is EK */ + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER asymSbuffer; + const unsigned char *asymBuffer; + uint32_t asymLength; + + printf(" TPM_Key_StoreClear:\n"); + TPM_Sbuffer_Init(&asymSbuffer); /* freed @1 */ + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, isEK, tpm_key); + } + /* store TPM_STORE_ASYMKEY cache as cleartext */ + if (rc == 0) { + /* if the TPM_STORE_ASYMKEY cache exists */ + if (tpm_key->tpm_store_asymkey != NULL) { + /* , serialize it */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&asymSbuffer, isEK, tpm_key->tpm_store_asymkey); + } + /* get the result */ + TPM_Sbuffer_Get(&asymSbuffer, &asymBuffer, &asymLength); + /* store the result as a sized buffer */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, asymLength); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, asymBuffer, asymLength); + } + } + /* If there is no TPM_STORE_ASYMKEY cache, mark it empty. This can occur for an internal + key that has not been created yet. */ + else { + rc = TPM_Sbuffer_Append32(sbuffer, 0); + } + } + TPM_Sbuffer_Delete(&asymSbuffer); /* @1 */ + return rc; +} + +/* TPM_KEY_StorePubkey() gets (as a stream) the TPM_PUBKEY derived from a TPM_KEY + + There is no need to actually assemble the structure, since only the serialization of its two + members are needed. + + The stream is returned as a TPM_STORE_BUFFER (that must be initialized and deleted by the + caller), and it's components (buffer and size). +*/ + +TPM_RESULT TPM_Key_StorePubkey(TPM_STORE_BUFFER *pubkeyStream, /* output */ + const unsigned char **pubkeyStreamBuffer, /* output */ + uint32_t *pubkeyStreamLength, /* output */ + TPM_KEY *tpm_key) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubkey:\n"); + /* the first part is a TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_Store(pubkeyStream, &(tpm_key->algorithmParms)); + } + /* the second part is the TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(pubkeyStream, &(tpm_key->pubKey)); + } + /* retrieve the resulting pubkey stream */ + if (rc == 0) { + TPM_Sbuffer_Get(pubkeyStream, + pubkeyStreamBuffer, + pubkeyStreamLength); + } + return rc; +} + +/* TPM_Key_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Key_Init to set members back to default values + The TPM_KEY itself is not freed + + The key is not freed because it might be a local variable rather than a malloc'ed pointer. +*/ + +void TPM_Key_Delete(TPM_KEY *tpm_key) +{ + if (tpm_key != NULL) { + printf(" TPM_Key_Delete:\n"); + TPM_KeyParms_Delete(&(tpm_key->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_key->pcrInfo)); + /* pcr caches */ + TPM_PCRInfo_Delete(tpm_key->tpm_pcr_info); + free(tpm_key->tpm_pcr_info); + TPM_PCRInfoLong_Delete(tpm_key->tpm_pcr_info_long); + free(tpm_key->tpm_pcr_info_long); + + TPM_SizedBuffer_Delete(&(tpm_key->pubKey)); + TPM_SizedBuffer_Delete(&(tpm_key->encData)); + TPM_StoreAsymkey_Delete(tpm_key->tpm_store_asymkey); + free(tpm_key->tpm_store_asymkey); + TPM_MigrateAsymkey_Delete(tpm_key->tpm_migrate_asymkey); + free(tpm_key->tpm_migrate_asymkey); + TPM_Key_Init(tpm_key); + } + return; +} + +/* TPM_Key_CheckStruct() verifies that the 'tpm_key' has either a TPM_KEY -> ver of a TPM_KEY12 tag + and fill +*/ + +TPM_RESULT TPM_Key_CheckStruct(int *ver, TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* The key can be either a TPM_KEY or TPM_KEY12 */ + if (*(unsigned char *)tpm_key == 0x01) { + *ver = 1; + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); /* check for TPM_KEY */ + if (rc == 0) { /* if found TPM_KEY */ + printf(" TPM_Key_CheckStruct: TPM_KEY version %u.%u\n", + tpm_key->ver.major, tpm_key->ver.minor); + } + } + else { /* else check for TPM_KEY12 */ + *ver = 2; + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + if (rc == 0) { + printf(" TPM_Key_CheckStruct: TPM_KEY12\n"); + } + else { /* not TPM_KEY or TPM_KEY12 */ + printf("TPM_Key_CheckStruct: Error checking structure, bytes 0:3 %02x %02x %02x %02x\n", + tpm_key->ver.major, tpm_key->ver.minor, + tpm_key->ver.revMajor, tpm_key->ver.revMinor); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckTag() checks that the TPM_KEY12 tag is correct + */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (tpm_key12->tag != TPM_TAG_KEY12) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 tag %04x should be TPM_TAG_KEY12\n", + tpm_key12->tag); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_key12->fill != 0x0000) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 fill %04x should be 0x0000\n", + tpm_key12->fill); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key'. + + if keyLength is non-zero, checks that the tpm_key specifies the correct key length. If keyLength + is 0, any tpm_key key length is accepted. + + Returns TPM_BAD_KEY_PROPERTY on error. + */ + +TPM_RESULT TPM_Key_CheckProperties(int *ver, + TPM_KEY *tpm_key, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_CheckProperties:\n"); + /* check the version */ + if (rc == 0) { + rc = TPM_Key_CheckStruct(ver, tpm_key); + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (tpm_key->authDataUsage == TPM_AUTH_NEVER) { + printf("TPM_Key_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* most of the work is done by TPM_KeyParms_CheckProperties() */ + if (rc == 0) { + printf(" TPM_Key_CheckProperties: authDataUsage %02x\n", tpm_key->authDataUsage); + rc = TPM_KeyParms_CheckProperties(&(tpm_key->algorithmParms), + tpm_key->keyUsage, + keyLength, /* in bits */ + FIPS); + } + return rc; +} + +/* TPM_Key_LoadStoreAsymKey() deserializes a stream to a TPM_STORE_ASYMKEY structure and stores it + in the TPM_KEY cache. + + Call this function when a key is loaded, either from the host (stream is decrypted encData) or + from permanent data or saved state (stream was clear text). +*/ + +TPM_RESULT TPM_Key_LoadStoreAsymKey(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, /* decrypted encData (clear text) */ + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* This function should never be called when the TPM_STORE_ASYMKEY structure has already been + loaded. This indicates an internal error. */ + printf(" TPM_Key_LoadStoreAsymKey:\n"); + if (rc == 0) { + if (tpm_key->tpm_store_asymkey != NULL) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), TPM_STORE_ASYMKEY already loaded\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* If the stream size is 0, there is an internal error. */ + if (rc == 0) { + if (*stream_size == 0) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), stream size is 0\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* allocate memory for the structure */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + rc = TPM_StoreAsymkey_Load(tpm_key->tpm_store_asymkey, isEK, + stream, stream_size, + &(tpm_key->algorithmParms), &(tpm_key->pubKey)); + TPM_PrintFour(" TPM_Key_LoadStoreAsymKey: usageAuth", + tpm_key->tpm_store_asymkey->usageAuth); + } + return rc; +} + +/* TPM_Key_GetStoreAsymkey() gets the TPM_STORE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetStoreAsymkey(TPM_STORE_ASYMKEY **tpm_store_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetStoreAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_store_asymkey = tpm_key->tpm_store_asymkey; + if (tpm_key->tpm_store_asymkey == NULL) { + printf("TPM_Key_GetStoreAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetMigrateAsymkey() gets the TPM_MIGRATE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetMigrateAsymkey(TPM_MIGRATE_ASYMKEY **tpm_migrate_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetMigrateAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_migrate_asymkey = tpm_key->tpm_migrate_asymkey; + if (tpm_key->tpm_migrate_asymkey == NULL) { + printf("TPM_Key_GetMigrateAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetUsageAuth() gets the usageAuth from the TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY + contained in a TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetUsageAuth(TPM_SECRET **usageAuth, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey; + + printf(" TPM_Key_GetUsageAuth:\n"); + /* check that the TPM_KEY_USAGE indicates a valid key */ + if (rc == 0) { + if ((tpm_key == NULL) || + (tpm_key->keyUsage == TPM_KEY_UNINITIALIZED)) { + printf("TPM_Key_GetUsageAuth: Error, key not initialized\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + + /* found a TPM_STORE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_store_asymkey->usageAuth); + } + /* get the TPM_MIGRATE_ASYMKEY object */ + else { + rc = TPM_Key_GetMigrateAsymkey(&tpm_migrate_asymkey, tpm_key); + /* found a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_migrate_asymkey->usageAuth); + } + } + } + if (rc != 0) { + printf("TPM_Key_GetUsageAuth: Error (fatal), " + "could not get TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY\n"); + rc = TPM_FAIL; /* should never occur */ + } + /* get the usageAuth element */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GetUsageAuth: Auth", **usageAuth); + } + return rc; +} + +/* TPM_Key_GetPublicKey() gets the public key from the TPM_STORE_PUBKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_key->pubKey.size; + *narr = tpm_key->pubKey.buffer; + } + return rc; +} + +/* TPM_Key_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY contained in a + TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrimeFactorP:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + } + return rc; +} + +/* TPM_Key_GetPrivateKey() gets the private key from the TPM_STORE_ASYMKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPrivateKey(uint32_t *dbytes, + unsigned char **darr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrivateKey:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *dbytes = tpm_store_asymkey->privKey.d_key.size; + *darr = tpm_store_asymkey->privKey.d_key.buffer; + } + return rc; +} + +/* TPM_Key_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_key->algorithmParms)); + } + return rc; +} + +/* TPM_Key_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_Key_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_KEY *tpm_key, + size_t start_index) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info, start_index); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info_long, start_index); + } + return rc; +} + +/* TPM_Key_GetLocalityAtRelease() the localityAtRelease for a TPM_PCR_INFO_LONG. + For a TPM_PCR_INFO is returns TPM_LOC_ALL (all localities). +*/ + +TPM_RESULT TPM_Key_GetLocalityAtRelease(TPM_LOCALITY_SELECTION *localityAtRelease, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetLocalityAtRelease:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* locality not used for TPM_PCR_INFO */ + *localityAtRelease = TPM_LOC_ALL; + } + /* TPM_KEY12 */ + else if (tpm_key->tpm_pcr_info_long == NULL) { + /* locality not used if TPM_PCR_INFO_LONG was not specified */ + *localityAtRelease = TPM_LOC_ALL; + } + else { + *localityAtRelease = tpm_key->tpm_pcr_info_long->localityAtRelease; + } + return rc; +} + +/* TPM_Key_GenerateRSA() generates a TPM_KEY using TPM_KEY_PARMS. The tag/version is set correctly. + + The TPM_STORE_ASYMKEY member cache is set. pcrInfo is set as a serialized tpm_pcr_info or + tpm_pcr_info_long. + + For exported keys, encData is not set yet. It later becomes the encryption of TPM_STORE_ASYMKEY. + + For internal 'root' keys (endorsement key, srk), encData is stored as clear text. + + It returns the TPM_KEY object. + + Call tree: + local - sets tpm_store_asymkey->privkey + TPM_Key_Set - sets keyUsage, keyFlags, authDataUsage, algorithmParms + tpm_pcr_info cache, digestAtCreation, pubKey, + TPM_Key_GeneratePubDataDigest - pubDataDigest + TPM_Key_Store + TPM_Key_StorePubData - serializes tpm_pcr_info cache +*/ + +TPM_RESULT TPM_Key_GenerateRSA(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* PCR array from state */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* input */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long) /* input */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + /* generated RSA key */ + unsigned char *n = NULL; /* public key */ + unsigned char *p = NULL; /* prime factor */ + unsigned char *q = NULL; /* prime factor */ + unsigned char *d = NULL; /* private key */ + + printf(" TPM_Key_GenerateRSA:\n"); + /* extract the TPM_RSA_KEY_PARMS from TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* get the public exponent, with conversion */ + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(&ebytes, &earr, tpm_rsa_key_parms); + } + /* allocate storage for TPM_STORE_ASYMKEY. The structure is not freed. It is cached in the + TPM_KEY->TPM_STORE_ASYMKEY member and freed when they are deleted. */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + } + /* generate the key pair */ + if (rc == 0) { + rc = TPM_RSAGenerateKeyPair(&n, /* public key (modulus) freed @3 */ + &p, /* private prime factor freed @4 */ + &q, /* private prime factor freed @5 */ + &d, /* private key (private exponent) freed @6 */ + tpm_rsa_key_parms->keyLength, /* key size in bits */ + earr, /* public exponent */ + ebytes); + } + /* construct the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GenerateRSA: Public key n", n); + TPM_PrintAll(" TPM_Key_GenerateRSA: Exponent", earr, ebytes); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime p", p); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime q", q); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private key d", d); + /* add the private primes and key to the TPM_STORE_ASYMKEY object */ + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.d_key), + tpm_rsa_key_parms->keyLength/CHAR_BIT, + d); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.p_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + p); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.q_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + q); + } + if (rc == 0) { + rc = TPM_Key_Set(tpm_key, + tpm_state, + parent_key, + tpm_pcrs, + ver, /* TPM_KEY or TPM_KEY12 */ + keyUsage, /* TPM_KEY_USAGE */ + keyFlags, /* TPM_KEY_FLAGS */ + authDataUsage, /* TPM_AUTH_DATA_USAGE */ + tpm_key_parms, /* TPM_KEY_PARMS */ + tpm_pcr_info, /* TPM_PCR_INFO */ + tpm_pcr_info_long, /* TPM_PCR_INFO_LONG */ + tpm_rsa_key_parms->keyLength/CHAR_BIT, /* TPM_STORE_PUBKEY.keyLength */ + n, /* TPM_STORE_PUBKEY.key (public key) */ + /* FIXME redundant */ + tpm_key->tpm_store_asymkey, /* cache the TPM_STORE_ASYMKEY structure */ + NULL); /* TPM_MIGRATE_ASYMKEY */ + } + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + return rc; +} + +/* TPM_Key_GeneratePubkeyDigest() serializes a TPM_PUBKEY derived from the TPM_KEY and calculates + its digest. +*/ + +TPM_RESULT TPM_Key_GeneratePubkeyDigest(TPM_DIGEST tpm_digest, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER pubkeyStream; /* from tpm_key */ + const unsigned char *pubkeyStreamBuffer; + uint32_t pubkeyStreamLength; + + printf(" TPM_Key_GeneratePubkeyDigest:\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* serialize a TPM_PUBKEY derived from the TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + tpm_key); /* input */ + } + if (rc == 0) { + rc = TPM_SHA1(tpm_digest, + pubkeyStreamLength, pubkeyStreamBuffer, + 0, NULL); + } + TPM_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rc; + +} + +/* TPM_Key_ComparePubkey() serializes and hashes the TPM_PUBKEY derived from a TPM_KEY and a + TPM_PUBKEY and compares the results +*/ + +TPM_RESULT TPM_Key_ComparePubkey(TPM_KEY *tpm_key, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + TPM_DIGEST key_digest; + TPM_DIGEST pubkey_digest; + + if (rc == 0) { + rc = TPM_Key_GeneratePubkeyDigest(key_digest, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(pubkey_digest, tpm_pubkey, + (TPM_STORE_FUNCTION_T)TPM_Pubkey_Store); + } + if (rc == 0) { + rc = TPM_Digest_Compare(key_digest, pubkey_digest); + } + return rc; +} + +/* TPM_Key_GeneratePubDataDigest() generates and stores a TPM_STORE_ASYMKEY -> pubDataDigest + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_GeneratePubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GeneratePubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_store_asymkey->pubDataDigest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_CheckPubDataDigest() generates a TPM_STORE_ASYMKEY -> pubDataDigest and compares it to + the stored value. + + Returns: Error id + */ + +TPM_RESULT TPM_Key_CheckPubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_DIGEST tpm_digest; /* calculated pubDataDigest */ + + printf(" TPM_Key_CheckPubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + if (rc == 0) { + rc = TPM_Digest_Compare(tpm_store_asymkey->pubDataDigest, tpm_digest); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_GenerateEncData() generates an TPM_KEY -> encData structure member by serializing the + cached TPM_KEY -> TPM_STORE_ASYMKEY member and encrypting the result using the parent_key public + key. +*/ + +TPM_RESULT TPM_Key_GenerateEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GenerateEncData;\n"); + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GenerateEncData(&(tpm_key->encData), + tpm_store_asymkey, + parent_key); + } + return rc; +} + + +/* TPM_Key_DecryptEncData() decrypts the TPM_KEY -> encData using the parent private key. The + result is deserialized and stored in the TPM_KEY -> TPM_STORE_ASYMKEY cache. + +*/ + +TPM_RESULT TPM_Key_DecryptEncData(TPM_KEY *tpm_key, /* result */ + TPM_KEY *parent_key) /* parent for decrypting encData */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Key_DecryptEncData\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted + data */ + tpm_key->encData.buffer, /* encrypted data */ + tpm_key->encData.size, /* encrypted data size */ + parent_key); + } + /* load the TPM_STORE_ASYMKEY cache from the 'encData' member stream */ + if (rc == 0) { + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_Key_LoadStoreAsymKey(tpm_key, FALSE, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + +/* TPM_Key_GeneratePCRDigest() generates a digest based on the current PCR state and the PCR's + specified with the key. + + The key can be either TPM_KEY or TPM_KEY12. + + This function assumes that TPM_Key_GetPCRUsage() has determined that PCR's are in use, so + a NULL PCR cache will return an error here. + + See Part 1 25.1 +*/ + +TPM_RESULT TPM_Key_CheckPCRDigest(TPM_KEY *tpm_key, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GeneratePCRDigest:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfo_CheckDigest(tpm_key->tpm_pcr_info, + tpm_state->tpm_stclear_data.PCRS); /* array of PCR's */ + } + } + else { /* TPM_KEY12 */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfoLong_CheckDigest(tpm_key->tpm_pcr_info_long, + tpm_state->tpm_stclear_data.PCRS, /* array of PCR's */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 4. Allow use of the key */ + if (rc != 0) { + printf("TPM_Key_CheckPCRDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + return rc; +} + +/* TPM_Key_CheckRestrictDelegate() checks the restrictDelegate data against the TPM_KEY properties. + It determines how the TPM responds to delegated requests to use a certified migration key. + + Called from TPM_AuthSessions_GetData() if it's a DSAP session using a key entity.. + + TPM_PERMANENT_DATA -> restrictDelegate is used as follows: + + 1. If the session type is TPM_PID_DSAP and TPM_KEY -> keyFlags -> migrateAuthority is TRUE + a. If + TPM_KEY_USAGE is TPM_KEY_SIGNING and restrictDelegate -> TPM_CMK_DELEGATE_SIGNING is TRUE, or + TPM_KEY_USAGE is TPM_KEY_STORAGE and restrictDelegate -> TPM_CMK_DELEGATE_STORAGE is TRUE, or + TPM_KEY_USAGE is TPM_KEY_BIND and restrictDelegate -> TPM_CMK_DELEGATE_BIND is TRUE, or + TPM_KEY_USAGE is TPM_KEY_LEGACY and restrictDelegate -> TPM_CMK_DELEGATE_LEGACY is TRUE, or + TPM_KEY_USAGE is TPM_KEY_MIGRATE and restrictDelegate -> TPM_CMK_DELEGATE_MIGRATE is TRUE + then the key can be used. + b. Else return TPM_INVALID_KEYUSAGE. + +*/ + +TPM_RESULT TPM_Key_CheckRestrictDelegate(TPM_KEY *tpm_key, + TPM_CMK_DELEGATE restrictDelegate) +{ + TPM_RESULT rc = 0; + + printf("TPM_Key_CheckRestrictDelegate:\n"); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_Key_CheckRestrictDelegate: Error (fatal), key NULL\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* if it's a certified migration key */ + if (rc == 0) { + if (tpm_key->keyFlags & TPM_MIGRATEAUTHORITY) { + if (!( + ((restrictDelegate & TPM_CMK_DELEGATE_SIGNING) && + (tpm_key->keyUsage == TPM_KEY_SIGNING)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_STORAGE) && + (tpm_key->keyUsage == TPM_KEY_STORAGE)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_BIND) && + (tpm_key->keyUsage == TPM_KEY_BIND)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_LEGACY) && + (tpm_key->keyUsage == TPM_KEY_LEGACY)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_MIGRATE) && + (tpm_key->keyUsage == TPM_KEY_MIGRATE)) + )) { + printf("TPM_Key_CheckRestrictDelegate: Error, " + "invalid keyUsage %04hx restrictDelegate %08x\n", + tpm_key->keyUsage, restrictDelegate); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + return rc; +} + +/* + TPM_KEY_FLAGS +*/ + +/* TPM_KeyFlags_Load() deserializes a TPM_KEY_FLAGS value and checks for a legal value. + */ + +TPM_RESULT TPM_KeyFlags_Load(TPM_KEY_FLAGS *tpm_key_flags, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + /* load keyFlags */ + if (rc == 0) { + rc = TPM_Load32(tpm_key_flags, stream, stream_size); + } + /* check TPM_KEY_FLAGS validity, look for extra bits set */ + if (rc == 0) { + if (*tpm_key_flags & ~TPM_KEY_FLAGS_MASK) { + printf("TPM_KeyFlags_Load: Error, illegal keyFlags value %08x\n", + *tpm_key_flags); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* + TPM_KEY_PARMS +*/ + +void TPM_KeyParms_Init(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Init:\n"); + tpm_key_parms->algorithmID = 0; + tpm_key_parms->encScheme = TPM_ES_NONE; + tpm_key_parms->sigScheme = TPM_SS_NONE; + TPM_SizedBuffer_Init(&(tpm_key_parms->parms)); + tpm_key_parms->tpm_rsa_key_parms = NULL; + return; +} + +#if 0 +/* TPM_KeyParms_SetRSA() is a 'Set' version specific to RSA keys */ + +TPM_RESULT TPM_KeyParms_SetRSA(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t keyLength, /* in bits */ + TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_SetRSA:\n"); + /* copy the TPM_KEY_PARMS members */ + if (rc == 0) { + tpm_key_parms->algorithmID = algorithmID; + tpm_key_parms->encScheme = encScheme; + tpm_key_parms->sigScheme = sigScheme; + /* construct the TPM_RSA_KEY_PARMS cache member object */ + rc = TPM_RSAKeyParms_New(&tpm_key_parms->tpm_rsa_key_parms); + } + if (rc == 0) { + /* copy the TPM_RSA_KEY_PARMS members */ + tpm_key_parms->tpm_rsa_key_parms->keyLength = keyLength; + tpm_key_parms->tpm_rsa_key_parms->numPrimes = 2; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms->tpm_rsa_key_parms->exponent), exponent); + } + /* serialize the TPM_RSA_KEY_PARMS object back to TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + } + return rc; +} +#endif + + +/* TPM_KeyParms_Copy() copies the source to the destination. + + If the algorithmID is TPM_ALG_RSA, the tpm_rsa_key_parms cache is allocated and copied. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Copy(TPM_KEY_PARMS *tpm_key_parms_dest, + TPM_KEY_PARMS *tpm_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Copy:\n"); + if (rc == 0) { + tpm_key_parms_dest->algorithmID = tpm_key_parms_src->algorithmID; + tpm_key_parms_dest->encScheme = tpm_key_parms_src->encScheme; + tpm_key_parms_dest->sigScheme = tpm_key_parms_src->sigScheme; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms_dest->parms), + &(tpm_key_parms_src->parms)); + } + /* if there is a destination TPM_RSA_KEY_PARMS cache */ + if ((rc == 0) && (tpm_key_parms_dest->algorithmID == TPM_ALG_RSA)) { + /* construct the TPM_RSA_KEY_PARMS cache member object */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms_dest->tpm_rsa_key_parms)); + } + /* copy the TPM_RSA_KEY_PARMS member */ + if (rc == 0) { + rc = TPM_RSAKeyParms_Copy(tpm_key_parms_dest->tpm_rsa_key_parms, + tpm_key_parms_src->tpm_rsa_key_parms); + } + } + return rc; +} + +/* TPM_KeyParms_Load deserializes a stream to a TPM_KEY_PARMS structure. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Load(TPM_KEY_PARMS *tpm_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + unsigned char *parms_stream; + uint32_t parms_stream_size; + + printf(" TPM_KeyParms_Load:\n"); + /* load algorithmID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_parms->algorithmID), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->encScheme), stream, stream_size); + } + /* load sigScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->sigScheme), stream, stream_size); + } + /* load parmSize and parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key_parms->parms), stream, stream_size); + } + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow load of uninitialized structures */ + case 0: + break; + + case TPM_ALG_RSA: + /* load the TPM_RSA_KEY_PARMS cache if the algorithmID indicates an RSA key */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms->tpm_rsa_key_parms)); + } + /* deserialize the parms stream, but don't move the pointer */ + if (rc == 0) { + parms_stream = tpm_key_parms->parms.buffer; + parms_stream_size = tpm_key_parms->parms.size; + rc = TPM_RSAKeyParms_Load(tpm_key_parms->tpm_rsa_key_parms, + &parms_stream, &parms_stream_size); + } + break; + + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Load: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + + printf(" TPM_KeyParms_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(ebytes, earr, tpm_rsa_key_parms); + } + return rc; +} + + +/* TPM_KeyParms_Store serializes a TPM_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_KeyParms_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Store:\n"); + /* store algorithmID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_parms->algorithmID); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->encScheme); + } + /* store sigScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->sigScheme); + } + /* copy cache to parms */ + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow store of uninitialized structures */ + case 0: + break; + case TPM_ALG_RSA: + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + break; + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Store: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + /* store parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key_parms->parms)); + } + return rc; +} + +/* TPM_KeyParms_Delete frees any member allocated memory */ + +void TPM_KeyParms_Delete(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Delete:\n"); + if (tpm_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_key_parms->parms)); + TPM_RSAKeyParms_Delete(tpm_key_parms->tpm_rsa_key_parms); + free(tpm_key_parms->tpm_rsa_key_parms); + TPM_KeyParms_Init(tpm_key_parms); + } + return; +} + +/* TPM_KeyParms_GetRSAKeyParms() gets the TPM_RSA_KEY_PARMS from a TPM_KEY_PARMS cache. + + Returns an error if the cache is NULL, since the cache should always be set when the + TPM_KEY_PARMS indicates an RSA key. +*/ + +TPM_RESULT TPM_KeyParms_GetRSAKeyParms(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_GetRSAKeyParms:\n"); + /* algorithmID must be RSA */ + if (rc == 0) { + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_GetRSAKeyParms: Error, incorrect algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if the TPM_RSA_KEY_PARMS structure has not been cached, deserialize it */ + if (rc == 0) { + if (tpm_key_parms->tpm_rsa_key_parms == NULL) { + printf("TPM_KeyParms_GetRSAKeyParms: Error (fatal), cache is NULL\n"); + /* This should never occur. The cache is loaded when the TPM_KEY_PARMS is loaded. */ + rc = TPM_FAIL; + } + } + /* return the cached structure */ + if (rc == 0) { + *tpm_rsa_key_parms = tpm_key_parms->tpm_rsa_key_parms; + } + return rc; +} + +/* TPM_KeyParms_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key_parms' + + if' keyLength' is non-zero, checks that the tpm_key specifies the correct key length. If + keyLength is 0, any tpm_key key length is accepted. +*/ + +TPM_RESULT TPM_KeyParms_CheckProperties(TPM_KEY_PARMS *tpm_key_parms, + TPM_KEY_USAGE tpm_key_usage, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms = NULL;/* used if algorithmID indicates RSA */ + + printf(" TPM_KeyParms_CheckProperties: keyUsage %04hx\n", tpm_key_usage); + printf(" TPM_KeyParms_CheckProperties: sigScheme %04hx\n", tpm_key_parms->sigScheme); + printf(" TPM_KeyParms_CheckProperties: encScheme %04hx\n", tpm_key_parms->encScheme); + if (rc == 0) { + /* the code currently only supports RSA */ + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_CheckProperties: Error, algorithmID not TPM_ALG_RSA\n"); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */ + /* NOTE: for now only support RSA keys */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* check key length if specified as input parameter */ + if ((rc == 0) && (keyLength != 0)) { + if (tpm_rsa_key_parms->keyLength != keyLength) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength should be %u, was %u\n", + keyLength, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_rsa_key_parms->keyLength > TPM_RSA_KEY_LENGTH_MAX) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength max %u, was %u\n", + TPM_RSA_KEY_LENGTH_MAX, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + + } + /* kgold - Support only 2 primes */ + if (rc == 0) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_KeyParms_CheckProperties: Error, numPrimes %u should be 2\n", + tpm_rsa_key_parms->numPrimes); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS */ + if (tpm_rsa_key_parms->keyLength < 1024) { + printf("TPM_KeyParms_CheckProperties: Error, Invalid FIPS key length %u\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_NOTFIPS; + } + /* c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS */ + else if (tpm_key_usage == TPM_KEY_LEGACY) { + printf("TPM_KeyParms_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* From Part 2 5.7.1 Mandatory Key Usage Schemes and TPM_CreateWrapKey, TPM_LoadKey */ + if (rc == 0) { + switch (tpm_key_usage) { + case TPM_KEY_UNINITIALIZED: + printf("TPM_KeyParms_CheckProperties: Error, keyUsage TPM_KEY_UNINITIALIZED\n"); + rc = TPM_BAD_KEY_PROPERTY; + break; + case TPM_KEY_SIGNING: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } +#ifdef TPM_V12 + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { +#else /* TPM 1.1 */ + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + +#endif + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing sigScheme %04hx is not DER, SHA1, INFO\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_STORAGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_IDENTITY: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity sigScheme %04hx is not %04x\n", + tpm_key_parms->sigScheme, TPM_SS_RSASSAPKCS1v15_SHA1); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_AUTHCHANGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_rsa_key_parms->keyLength < 512) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange keyLength %d is less than 512\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_BIND: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_LEGACY: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy sigScheme %04hx is not %04x or %04x\n", + tpm_key_parms->sigScheme, + TPM_SS_RSASSAPKCS1v15_SHA1, TPM_SS_RSASSAPKCS1v15_DER); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_MIGRATE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + default: + printf("TPM_KeyParms_CheckProperties: Error, Unknown keyUsage %04hx\n", tpm_key_usage); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParams_CheckDefaultExponent(TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + uint32_t i; + + if ((rc == 0) && (exponent->size != 0)) { /* 0 is the default */ + printf(" TPM_KeyParams_CheckDefaultExponent: exponent size %u\n", exponent->size); + if (rc == 0) { + if (exponent->size < 3) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent size is %u\n", + exponent->size); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + for (i = 3 ; i < exponent->size ; i++) { + if (exponent->buffer[i] != 0) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent[%u] is %02x\n", + i, exponent->buffer[i]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + if (rc == 0) { + if ((exponent->buffer[0] != tpm_default_rsa_exponent[0]) || + (exponent->buffer[1] != tpm_default_rsa_exponent[1]) || + (exponent->buffer[2] != tpm_default_rsa_exponent[2])) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent is %02x %02x %02x\n", + exponent->buffer[2], exponent->buffer[1], exponent->buffer[0]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + return rc; +} + +/* + TPM_STORE_ASYMKEY +*/ + +void TPM_StoreAsymkey_Init(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Init:\n"); + tpm_store_asymkey->payload = TPM_PT_ASYM; + TPM_Secret_Init(tpm_store_asymkey->usageAuth); + TPM_Secret_Init(tpm_store_asymkey->migrationAuth); + TPM_Digest_Init(tpm_store_asymkey->pubDataDigest); + TPM_StorePrivkey_Init(&(tpm_store_asymkey->privKey)); + return; +} + +/* TPM_StoreAsymkey_Load() deserializes the TPM_STORE_ASYMKEY structure. + + The serialized structure contains the private factor p. Normally, 'tpm_key_parms' and + tpm_store_pubkey are not NULL and the private key d is derived from p and the public key n and + exponent e. + + In some cases, a TPM_STORE_ASYMKEY is being manipulated without the rest of the TPM_KEY + structure. When 'tpm_key' is NULL, p is left intact, and the resulting structure cannot be used + as a private key. +*/ + +TPM_RESULT TPM_StoreAsymkey_Load(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *pubKey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Load:\n"); + /* load payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Load8(&(tpm_store_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if ((rc == 0) && !isEK) { + if ( + /* normal key */ + (tpm_store_asymkey->payload != TPM_PT_ASYM) && + /* TPM_CMK_CreateKey payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + /* TPM_CMK_ConvertMigration payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_EXTERNAL) + ) { + printf("TPM_StoreAsymkey_Load: Error, invalid payload %02x\n", + tpm_store_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->usageAuth, stream, stream_size); + } + /* load migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->migrationAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_store_asymkey->pubDataDigest, stream, stream_size); + } + /* load privKey - actually prime factor p */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load((&(tpm_store_asymkey->privKey.p_key)), + stream, stream_size); + } + /* convert prime factor p to the private key */ + if ((rc == 0) && (tpm_key_parms != NULL) && (pubKey != NULL)) { + rc = TPM_StorePrivkey_Convert(tpm_store_asymkey, + tpm_key_parms, pubKey); + } + return rc; +} + +#if 0 +static TPM_RESULT TPM_StoreAsymkey_LoadTest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + int irc; + + /* actual */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr; + unsigned char *darr; + + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + /* computed */ + unsigned char *q1arr = NULL; + unsigned char *d1arr = NULL; + + uint32_t q1bytes; + uint32_t d1bytes; + + printf(" TPM_StoreAsymkey_LoadTest:\n"); + /* actual data */ + if (rc == 0) { + narr = tpm_key->pubKey.key; + darr = tpm_key->tpm_store_asymkey->privKey.d_key; + parr = tpm_key->tpm_store_asymkey->privKey.p_key; + qarr = tpm_key->tpm_store_asymkey->privKey.q_key; + + nbytes = tpm_key->pubKey.keyLength; + dbytes = tpm_key->tpm_store_asymkey->privKey.d_keyLength; + pbytes = tpm_key->tpm_store_asymkey->privKey.p_keyLength; + qbytes = tpm_key->tpm_store_asymkey->privKey.q_keyLength; + + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetPrimeFactorP(&pbytes, &parr, tpm_key); + } + /* computed data */ + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&q1bytes, &q1arr, /* freed @1 */ + &d1bytes, &d1arr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + /* compare q */ + if (rc == 0) { + if (qbytes != q1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qbytes %u q1bytes %u\n", + qbytes, q1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(qarr, q1arr, qbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qarr mismatch\n"); + rc = TPM_FAIL; + } + } + /* compare d */ + if (rc == 0) { + if (dbytes != d1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), dbytes %u d1bytes %u\n", + dbytes, d1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(darr, d1arr, dbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), darr mismatch\n"); + rc = TPM_FAIL; + } + } + free(q1arr); /* @1 */ + free(d1arr); /* @2 */ + return rc; +} +#endif + +TPM_RESULT TPM_StoreAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + const TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Store:\n"); + /* store payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_store_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->usageAuth); + } + /* store migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->migrationAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_store_asymkey->pubDataDigest); + } + /* store privKey */ + if (rc == 0) { + rc = TPM_StorePrivkey_Store(sbuffer, &(tpm_store_asymkey->privKey)); + } + return rc; +} + +void TPM_StoreAsymkey_Delete(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Delete:\n"); + if (tpm_store_asymkey != NULL) { + TPM_Secret_Delete(tpm_store_asymkey->usageAuth); + TPM_Secret_Delete(tpm_store_asymkey->migrationAuth); + TPM_StorePrivkey_Delete(&(tpm_store_asymkey->privKey)); + TPM_StoreAsymkey_Init(tpm_store_asymkey); + } + return; +} + +TPM_RESULT TPM_StoreAsymkey_GenerateEncData(TPM_SIZED_BUFFER *encData, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORE_ASYMKEY serialization */ + + printf(" TPM_StoreAsymkey_GenerateEncData;\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(encData, &sbuffer, parent_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_StoreAsymkey_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY +*/ + +TPM_RESULT TPM_StoreAsymkey_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_GetPrimeFactorP:\n"); + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + TPM_PrintFour(" TPM_StoreAsymkey_GetPrimeFactorP:", *parr); + } + return rc; +} + +/* TPM_StoreAsymkey_GetO1Size() calculates the destination o1 size for a TPM_STORE_ASYMKEY + + Used for creating a migration blob, TPM_STORE_ASYMKEY -> TPM_MIGRATE_ASYMKEY. + */ + +void TPM_StoreAsymkey_GetO1Size(uint32_t *o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + *o1_size = tpm_store_asymkey->privKey.p_key.size + /* private key */ + sizeof(uint32_t) - /* private key length */ + TPM_DIGEST_SIZE + /* - k1 -> k2 TPM_MIGRATE_ASYMKEY -> partPrivKey */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1; /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_GetO1Size: key size %u o1 size %u\n", + tpm_store_asymkey->privKey.p_key.size, *o1_size); +} + +/* TPM_StoreAsymkey_CheckO1Size() verifies the destination o1_size against the source k1k2 array + length + + This is a currently just a sanity check on the TPM_StoreAsymkey_GetO1Size() function. +*/ + +TPM_RESULT TPM_StoreAsymkey_CheckO1Size(uint32_t o1_size, + uint32_t k1k2_length) +{ + TPM_RESULT rc = 0; + + /* sanity check the TPM_MIGRATE_ASYMKEY size against the requested o1 size */ + /* K1 K2 are the length and value of the private key, 4 + 128 bytes for a 2048-bit key */ + if (o1_size < + (k1k2_length - TPM_DIGEST_SIZE + /* k1 k2, the first 20 bytes are used as the OAEP seed */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1)) { /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_CheckO1Size: Error (fatal) k1k2_length %d too large for o1 %u\n", + k1k2_length, o1_size); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_StoreAsymkey_StoreO1() creates an OAEP encoded TPM_MIGRATE_ASYMKEY from a + TPM_STORE_ASYMKEY. + + It does the common steps of constructing the TPM_MIGRATE_ASYMKEY, serializing it, and OAEP + padding. +*/ + +TPM_RESULT TPM_StoreAsymkey_StoreO1(BYTE *o1, + uint32_t o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SECRET usageAuth) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER k1k2_sbuffer; /* serialization of TPM_STORE_ASYMKEY -> privKey -> key */ + const unsigned char *k1k2; /* serialization results */ + uint32_t k1k2_length; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER tpm_migrate_asymkey_sbuffer; /* serialized tpm_migrate_asymkey */ + const unsigned char *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + + printf(" TPM_StoreAsymkey_StoreO1:\n"); + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @1 */ + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @2 */ + TPM_Sbuffer_Init(&tpm_migrate_asymkey_sbuffer); /* freed @3 */ + + /* NOTE Comments from TPM_CreateMigrationBlob rev 81 */ + /* a. Build two byte arrays, K1 and K2: */ + /* i. K1 = TPM_STORE_ASYMKEY.privKey[0..19] (TPM_STORE_ASYMKEY.privKey.keyLength + 16 bytes of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K1) = 20 */ + /* ii. K2 = TPM_STORE_ASYMKEY.privKey[20..131] (position 16-127 of + TPM_STORE_ASYMKEY. privKey.key), sizeof(K2) = 112 */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(&k1k2_sbuffer, &(tpm_store_asymkey->privKey.p_key)); + } + if (rc == 0) { + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2, &k1k2_length); + /* sanity check the TPM_STORE_ASYMKEY -> privKey -> key size against the requested o1 + size */ + rc = TPM_StoreAsymkey_CheckO1Size(o1_size, k1k2_length); + } + /* b. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* i. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_MIGRATE */ + /* ii. TPM_MIGRATE_ASYMKEY.usageAuth = TPM_STORE_ASYMKEY.usageAuth */ + /* iii. TPM_MIGRATE_ASYMKEY.pubDataDigest = TPM_STORE_ASYMKEY. pubDataDigest */ + /* iv. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* v. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + if (rc == 0) { + tpm_migrate_asymkey.payload = payload_type; + TPM_Secret_Copy(tpm_migrate_asymkey.usageAuth, usageAuth); + TPM_Digest_Copy(tpm_migrate_asymkey.pubDataDigest, tpm_store_asymkey->pubDataDigest); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k1 -", k1k2); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k2 -", k1k2 + TPM_DIGEST_SIZE); + rc = TPM_SizedBuffer_Set(&(tpm_migrate_asymkey.partPrivKey), + k1k2_length - TPM_DIGEST_SIZE, /* k2 length 112 for 2048 bit key */ + k1k2 + TPM_DIGEST_SIZE); /* k2 */ + } + /* c. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* i. m = M1 the TPM_MIGRATE_ASYMKEY structure */ + /* ii. pHash = d1->migrationAuth */ + /* iii. seed = s1 = K1 */ + if (rc == 0) { + /* serialize TPM_MIGRATE_ASYMKEY m */ + rc = TPM_MigrateAsymkey_Store(&tpm_migrate_asymkey_sbuffer, &tpm_migrate_asymkey); + } + if (rc == 0) { + /* get the serialization result */ + TPM_Sbuffer_Get(&tpm_migrate_asymkey_sbuffer, + &tpm_migrate_asymkey_buffer, &tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: pHash -", pHash); + rc = TPM_RSA_padding_add_PKCS1_OAEP(o1, /* output */ + o1_size, + tpm_migrate_asymkey_buffer, /* message */ + tpm_migrate_asymkey_length, + pHash, + k1k2); /* k1, seed */ + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: o1 -", o1); + } + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @1 */ + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @2 */ + TPM_Sbuffer_Delete(&tpm_migrate_asymkey_sbuffer); /* @3 */ + return rc; +} + +/* TPM_StoreAsymkey_LoadO1() extracts TPM_STORE_ASYMKEY from the OAEP encoded TPM_MIGRATE_ASYMKEY. + + It does the common steps OAEP depadding, deserializing the TPM_MIGRATE_ASYMKEY, and + reconstructing the TPM_STORE_ASYMKEY. + + It sets these, which may or may not be correct at a higher level + + TPM_STORE_ASYMKEY -> payload = TPM_MIGRATE_ASYMKEY -> payload + TPM_STORE_ASYMKEY -> usageAuth = TPM_MIGRATE_ASYMKEY -> usageAuth + TPM_STORE_ASYMKEY -> migrationAuth = pHash + TPM_STORE_ASYMKEY -> pubDataDigest = TPM_MIGRATE_ASYMKEY -> pubDataDigest + TPM_STORE_ASYMKEY -> privKey = seed + TPM_MIGRATE_ASYMKEY -> partPrivKey +*/ + +TPM_RESULT TPM_StoreAsymkey_LoadO1(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* output */ + BYTE *o1, /* input */ + uint32_t o1_size) /* input */ +{ + TPM_RESULT rc = 0; + BYTE *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + TPM_DIGEST seed; + TPM_DIGEST pHash; + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER k1k2_sbuffer; + const unsigned char *k1k2_buffer; + uint32_t k1k2_length; + + printf(" TPM_StoreAsymkey_LoadO1:\n"); + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @1 */ + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @2 */ + tpm_migrate_asymkey_buffer = NULL; /* freed @3 */ + /* allocate memory for TPM_MIGRATE_ASYMKEY after removing OAEP pad from o1 */ + if (rc == 0) { + rc = TPM_Malloc(&tpm_migrate_asymkey_buffer, o1_size); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: o1 -", o1); + /* 5. Create m1, seed and pHash by OAEP decoding o1 */ + printf(" TPM_StoreAsymkey_LoadO1: Depadding\n"); + rc = TPM_RSA_padding_check_PKCS1_OAEP(tpm_migrate_asymkey_buffer, /* out: to */ + &tpm_migrate_asymkey_length, /* out: to length */ + o1_size, /* to size */ + o1, o1_size, /* from, from length */ + pHash, + seed); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_buffer -", + tpm_migrate_asymkey_buffer); + printf(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_length %u\n", + tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - pHash", pHash); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - seed", seed); + } + /* deserialize the buffer back to a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + stream = tpm_migrate_asymkey_buffer; + stream_size = tpm_migrate_asymkey_length; + rc = TPM_MigrateAsymkey_Load(&tpm_migrate_asymkey, &stream, &stream_size); + printf(" TPM_StoreAsymkey_LoadO1: partPrivKey length %u\n", + tpm_migrate_asymkey.partPrivKey.size); + TPM_PrintFourLimit(" TPM_StoreAsymkey_LoadO1: partPrivKey -", + tpm_migrate_asymkey.partPrivKey.buffer, + tpm_migrate_asymkey.partPrivKey.size); + } + /* create k1k2 by combining seed (k1) and TPM_MIGRATE_ASYMKEY.partPrivKey (k2) field */ + if (rc == 0) { + rc = TPM_Digest_Store(&k1k2_sbuffer, seed); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(&k1k2_sbuffer, + tpm_migrate_asymkey.partPrivKey.buffer, + tpm_migrate_asymkey.partPrivKey.size); + } + /* assemble the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + tpm_store_asymkey->payload = tpm_migrate_asymkey.payload; + TPM_Digest_Copy(tpm_store_asymkey->usageAuth, tpm_migrate_asymkey.usageAuth); + TPM_Digest_Copy(tpm_store_asymkey->migrationAuth, pHash); + TPM_Digest_Copy(tpm_store_asymkey->pubDataDigest, tpm_migrate_asymkey.pubDataDigest); + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2_buffer, &k1k2_length); + printf(" TPM_StoreAsymkey_LoadO1: k1k2 length %u\n", k1k2_length); + TPM_PrintFourLimit(" TPM_StoreAsymkey_LoadO1: k1k2", k1k2_buffer, k1k2_length); + rc = TPM_SizedBuffer_Load(&(tpm_store_asymkey->privKey.p_key), + (unsigned char **)&k1k2_buffer, &k1k2_length); + } + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @1 */ + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @2 */ + free(tpm_migrate_asymkey_buffer); /* @3 */ + return rc; +} + + +/* + TPM_MIGRATE_ASYMKEY +*/ + +/* TPM_MigrateAsymkey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_MigrateAsymkey_Init(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Init:\n"); + tpm_migrate_asymkey->payload = TPM_PT_MIGRATE; + TPM_Secret_Init(tpm_migrate_asymkey->usageAuth); + TPM_Digest_Init(tpm_migrate_asymkey->pubDataDigest); + TPM_SizedBuffer_Init(&(tpm_migrate_asymkey->partPrivKey)); + return; +} + +/* TPM_MigrateAsymkey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_MigrateAsymkey_Init() + After use, call TPM_MigrateAsymkey_Delete() to free memory +*/ + +TPM_RESULT TPM_MigrateAsymkey_Load(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_migrate_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if (rc == 0) { + if ((tpm_migrate_asymkey->payload != TPM_PT_MIGRATE) && + (tpm_migrate_asymkey->payload != TPM_PT_MAINT) && + (tpm_migrate_asymkey->payload != TPM_PT_CMK_MIGRATE)) { + printf("TPM_MigrateAsymkey_Load: Error illegal payload %02x\n", + tpm_migrate_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_migrate_asymkey->usageAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_migrate_asymkey->pubDataDigest, stream, stream_size); + } + /* load partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_migrate_asymkey->partPrivKey), stream, stream_size); + } + return rc; +} + +/* TPM_MigrateAsymkey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_MigrateAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_migrate_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_migrate_asymkey->usageAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_migrate_asymkey->pubDataDigest); + } + /* store partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_migrate_asymkey->partPrivKey)); + } + return rc; +} + +/* TPM_MigrateAsymkey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_MigrateAsymkey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_MigrateAsymkey_Delete(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Delete:\n"); + if (tpm_migrate_asymkey != NULL) { + TPM_Secret_Delete(tpm_migrate_asymkey->usageAuth); + TPM_SizedBuffer_Zero(&(tpm_migrate_asymkey->partPrivKey)); + TPM_SizedBuffer_Delete(&(tpm_migrate_asymkey->partPrivKey)); + TPM_MigrateAsymkey_Init(tpm_migrate_asymkey); + } + return; +} + +/* + TPM_STORE_PRIVKEY +*/ + +void TPM_StorePrivkey_Init(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Init:\n"); + TPM_SizedBuffer_Init(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->q_key)); + return; +} + +/* TPM_StorePrivkey_Convert() sets the prime factor q and private key d based on the prime factor p + and the public key and exponent. +*/ + +TPM_RESULT TPM_StorePrivkey_Convert(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* I/O result */ + TPM_KEY_PARMS *tpm_key_parms, /* to get exponent */ + TPM_SIZED_BUFFER *pubKey) /* to get public key */ +{ + TPM_RESULT rc = 0; + /* computed data */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr = NULL; + unsigned char *darr = NULL; + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + + printf(" TPM_StorePrivkey_Convert:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: p", tpm_store_asymkey->privKey.p_key.buffer); + nbytes = pubKey->size; + narr = pubKey->buffer; + rc = TPM_KeyParms_GetExponent(&ebytes, &earr, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GetPrimeFactorP(&pbytes, &parr, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&qbytes, &qarr, /* freed @1 */ + &dbytes, &darr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: q", qarr); + TPM_PrintFour(" TPM_StorePrivkey_Convert: d", darr); + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.q_key)), qbytes, qarr); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.d_key)), dbytes, darr); + } + free(qarr); /* @1 */ + free(darr); /* @2 */ + return rc; +} + +/* TPM_StorePrivkey_Store serializes a TPM_STORE_PRIVKEY structure, appending results to 'sbuffer' + + Only the prime factor p is stored. The other prime factor q and the private key d are + recalculated after a load. + */ + +TPM_RESULT TPM_StorePrivkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StorePrivkey_Store:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Store: p", tpm_store_privkey->p_key.buffer); + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_store_privkey->p_key)); + } + return rc; +} + +void TPM_StorePrivkey_Delete(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Delete:\n"); + if (tpm_store_privkey != NULL) { + TPM_SizedBuffer_Zero(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->q_key)); + + TPM_SizedBuffer_Delete(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->q_key)); + TPM_StorePrivkey_Init(tpm_store_privkey); + } + return; +} + +/* + TPM_PUBKEY +*/ + +void TPM_Pubkey_Init(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Init:\n"); + TPM_KeyParms_Init(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_pubkey->pubKey)); + return; +} + +TPM_RESULT TPM_Pubkey_Load(TPM_PUBKEY *tpm_pubkey, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Load:\n"); + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_pubkey->algorithmParms), stream, stream_size); + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_pubkey->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Pubkey_Store serializes a TPM_PUBKEY structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_Pubkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Store:\n"); + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_pubkey->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_pubkey->pubKey)); + } + return rc; +} + +void TPM_Pubkey_Delete(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Delete:\n"); + if (tpm_pubkey != NULL) { + TPM_KeyParms_Delete(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Delete(&(tpm_pubkey->pubKey)); + TPM_Pubkey_Init(tpm_pubkey); + } + return; +} + +TPM_RESULT TPM_Pubkey_Set(TPM_PUBKEY *tpm_pubkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Set:\n"); + if (rc == 0) { + /* add TPM_KEY_PARMS algorithmParms */ + rc = TPM_KeyParms_Copy(&(tpm_pubkey->algorithmParms), + &(tpm_key->algorithmParms)); + } + if (rc == 0) { + /* add TPM_SIZED_BUFFER pubKey */ + rc = TPM_SizedBuffer_Copy(&(tpm_pubkey->pubKey), + &(tpm_key->pubKey)); + } + return rc; +} + +TPM_RESULT TPM_Pubkey_Copy(TPM_PUBKEY *dest_tpm_pubkey, + TPM_PUBKEY *src_tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Copy:\n"); + /* copy TPM_KEY_PARMS algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(dest_tpm_pubkey->algorithmParms), + &(src_tpm_pubkey->algorithmParms)); + } + /* copy TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(dest_tpm_pubkey->pubKey), + &(src_tpm_pubkey->pubKey)); + } + return rc; + +} + +/* TPM_Pubkey_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a + TPM_PUBKEY +*/ + +TPM_RESULT TPM_Pubkey_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_pubkey->algorithmParms)); + } + return rc; +} + +/* TPM_Pubkey_GetPublicKey() gets the public key from the TPM_PUBKEY + */ + +TPM_RESULT TPM_Pubkey_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_pubkey->pubKey.size; + *narr = tpm_pubkey->pubKey.buffer; + } + return rc; +} + +/* + TPM_RSA_KEY_PARMS +*/ + + +/* Allocates and loads a TPM_RSA_KEY_PARMS structure + + Must be delete'd and freed by the caller. +*/ + +void TPM_RSAKeyParms_Init(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Init:\n"); + tpm_rsa_key_parms->keyLength = 0; + tpm_rsa_key_parms->numPrimes = 0; + TPM_SizedBuffer_Init(&(tpm_rsa_key_parms->exponent)); + return; +} + +/* TPM_RSAKeyParms_Load() sets members from stream, and shifts the stream past the bytes consumed. + + Must call TPM_RSAKeyParms_Delete() to free +*/ + +TPM_RESULT TPM_RSAKeyParms_Load(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Load:\n"); + /* load keyLength */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->keyLength), stream, stream_size); + } + /* load numPrimes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->numPrimes), stream, stream_size); + } + /* load exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_rsa_key_parms->exponent), stream, stream_size); + } + return rc; +} + +/* TPM_RSAKeyParms_Store serializes a TPM_RSA_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_RSAKeyParms_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Store:\n"); + /* store keyLength */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->keyLength); + } + /* store numPrimes */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->numPrimes); + } + /* store exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_rsa_key_parms->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_Delete frees any member allocated memory + + If 'tpm_rsa_key_parms' is NULL, this is a no-op. + */ + +void TPM_RSAKeyParms_Delete(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Delete:\n"); + if (tpm_rsa_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_rsa_key_parms->exponent)); + TPM_RSAKeyParms_Init(tpm_rsa_key_parms); + } + return; +} + +/* TPM_RSAKeyParms_Copy() does a copy of the source to the destination. + + The destination must be initialized first. +*/ + +TPM_RESULT TPM_RSAKeyParms_Copy(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_dest, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Copy:\n"); + if (rc == 0) { + tpm_rsa_key_parms_dest->keyLength = tpm_rsa_key_parms_src->keyLength; + tpm_rsa_key_parms_dest->numPrimes = tpm_rsa_key_parms_src->numPrimes; + rc = TPM_SizedBuffer_Copy(&(tpm_rsa_key_parms_dest->exponent), + &(tpm_rsa_key_parms_src->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_New() allocates memory for a TPM_RSA_KEY_PARMS and initializes the structure */ + +TPM_RESULT TPM_RSAKeyParms_New(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_New:\n"); + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_rsa_key_parms, sizeof(TPM_RSA_KEY_PARMS)); + } + if (rc == 0) { + TPM_RSAKeyParms_Init(*tpm_rsa_key_parms); + } + return rc; +} + +/* TPM_RSAKeyParms_GetExponent() gets the exponent array and size from tpm_rsa_key_parms. + + If the structure exponent.size is zero, the default RSA exponent is returned. +*/ + +TPM_RESULT TPM_RSAKeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_GetExponent:\n"); + if (tpm_rsa_key_parms->exponent.size != 0) { + *ebytes = tpm_rsa_key_parms->exponent.size; + *earr = tpm_rsa_key_parms->exponent.buffer; + } + else { + *ebytes = 3; + *earr = tpm_default_rsa_exponent; + } + return rc; +} + +/* + A Key Handle Entry +*/ + +/* TPM_KeyHandleEntry_Init() removes an entry from the list. It DOES NOT delete the + TPM_KEY object. */ + +void TPM_KeyHandleEntry_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + tpm_key_handle_entry->handle = 0; + tpm_key_handle_entry->key = NULL; + tpm_key_handle_entry->parentPCRStatus = TRUE; + tpm_key_handle_entry->keyControl = 0; + return; +} + +/* TPM_KeyHandleEntry_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_KeyHandleEntry_Init() + After use, call TPM_KeyHandleEntry_Delete() to free memory +*/ + +TPM_RESULT TPM_KeyHandleEntry_Load(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Load:\n"); + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->handle), stream, stream_size); + } + /* malloc space for the key member */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key_handle_entry->key), sizeof(TPM_KEY)); + } + /* load key */ + if (rc == 0) { + TPM_Key_Init(tpm_key_handle_entry->key); + rc = TPM_Key_LoadClear(tpm_key_handle_entry->key, + FALSE, /* not EK */ + stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_key_handle_entry->parentPCRStatus), stream, stream_size); + } + /* load keyControl */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->keyControl), stream, stream_size); + } + return rc; +} + +/* TPM_KeyHandleEntry_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_KeyHandleEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Store:\n"); + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->handle); + } + /* store key with private data appended in clear text */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, + FALSE, /* not EK */ + tpm_key_handle_entry->key); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_key_handle_entry->parentPCRStatus), sizeof(TPM_BOOL)); + } + /* store keyControl */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->keyControl); + } + return rc; +} + +/* TPM_KeyHandleEntry_Delete() deletes an entry from the list, deletes the TPM_KEY object, and + free's the TPM_KEY. +*/ + +void TPM_KeyHandleEntry_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + if (tpm_key_handle_entry != NULL) { + if (tpm_key_handle_entry->handle != 0) { + printf(" TPM_KeyHandleEntry_Delete: Deleting %08x\n", tpm_key_handle_entry->handle); + TPM_Key_Delete(tpm_key_handle_entry->key); + free(tpm_key_handle_entry->key); + } + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return; +} + +/* TPM_KeyHandleEntry_FlushSpecific() flushes a key handle according to the rules of + TPM_FlushSpecific() +*/ + +TPM_RESULT TPM_KeyHandleEntry_FlushSpecific(tpm_state_t *tpm_state, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + TPM_AUTHHANDLE authHandle = 0; /* dummy parameter */ + TPM_BOOL continueAuthSession; /* dummy parameter */ + + printf(" TPM_KeyHandleEntry_FlushSpecific:\n"); + if (rc == 0) { + /* Internal error, should never happen */ + if (tpm_key_handle_entry->key == NULL) { + printf("TPM_KeyHandleEntry_FlushSpecific: Error (fatal), key is NULL\n"); + rc = TPM_FAIL; + } + } + /* terminate OSAP and DSAP sessions associated with the key */ + if (rc == 0) { + /* The dummy parameters are not used. The session, if any, associated with this function + is handled elsewhere. */ + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_KEYHANDLE, /* TPM_ENTITY_TYPE */ + &(tpm_key_handle_entry->key-> + tpm_store_asymkey->pubDataDigest)); /* entityDigest */ + printf(" TPM_KeyHandleEntry_FlushSpecific: Flushing key handle %08x\n", + tpm_key_handle_entry->handle); + /* free the TPM_KEY resources, free the key itself, and remove entry from the key handle + entries list */ + TPM_KeyHandleEntry_Delete(tpm_key_handle_entry); + } + return rc; +} + +/* + Key Handle Entries +*/ + +/* TPM_KeyHandleEntries_Init() initializes the fixed TPM_KEY_HANDLE_ENTRY array. All entries are + emptied. The keys are not deleted. +*/ + +void TPM_KeyHandleEntries_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Init:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Init(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Delete() deletes and freed all TPM_KEY's stored in entries, and the entry + +*/ + +void TPM_KeyHandleEntries_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Delete:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Load() loads the key handle entries from a stream created by + TPM_KeyHandleEntries_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t keyCount = 0; /* keys to be saved */ + size_t i; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY_HANDLE_ENTRIES_V1, stream, stream_size); + } + /* get the count of keys in the stream */ + if (rc == 0) { + rc = TPM_Load32(&keyCount, stream, stream_size); + printf(" TPM_KeyHandleEntries_Load: %u keys to be loaded\n", keyCount); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_Load: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_KEY_HANDLES); + rc = TPM_FAIL; + } + } + /* for each key handle entry */ + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* deserialize the key handle entry and its key member */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Load: Loading key handle %08x\n", + tpm_key_handle_entry.handle); + /* Add the entry to the list. Keep the handle. If the suggested value could not be + accepted, this is a "should never happen" fatal error. It means that the save key + handle was saved twice. */ + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_Store() stores the key handle entries to a stream that can be restored + through TPM_KeyHandleEntries_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + size_t start; /* iterator though key handle entries */ + size_t current; /* iterator though key handle entries */ + uint32_t keyCount; /* keys to be saved */ + TPM_BOOL save; /* should key be saved */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY_HANDLE_ENTRIES_V1); + } + /* first count up the keys */ + if (rc == 0) { + start = 0; + keyCount = 0; + printf(" TPM_KeyHandleEntries_Store: Counting keys to be stored\n"); + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + keyCount++; + } + start = current + 1; + } + /* store the number of entries to save */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: %u keys to be stored\n", keyCount); + rc = TPM_Sbuffer_Append32(sbuffer, keyCount); + } + /* for each key handle entry */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: Storing keys\n"); + start = 0; + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + /* store the key handle entry and its associated key */ + rc = TPM_KeyHandleEntry_Store(sbuffer, tpm_key_handle_entry); + } + start = current + 1; + } + return rc; +} + + + +/* TPM_KeyHandleEntries_StoreHandles() stores only the two members which are part of the + specification. + + - the number of loaded keys + - a list of key handles + + A TPM_KEY_HANDLE_LIST structure that enumerates all key handles loaded on the TPM. The list only + contains the number of handles that an external manager can operate with and does not include the + EK or SRK. This is command is available for backwards compatibility. It is the same as + TPM_CAP_HANDLE with a resource type of keys. +*/ + +TPM_RESULT TPM_KeyHandleEntries_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i, loadedCount; + + printf(" TPM_KeyHandleEntries_StoreHandles:\n"); + if (rc == 0) { + loadedCount = 0; + /* count the number of loaded handles */ + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { + loadedCount++; + } + } + /* store 'loaded' handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loadedCount); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entries[i].handle); /* store it */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_DeleteHandle() removes a handle from the list. + + The TPM_KEY object must be _Delete'd and possibly free'd separately, because it might not be in + the table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_DeleteHandle(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_DeleteHandle: %08x\n", tpm_key_handle); + /* search for the handle */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_DeleteHandle: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* delete the entry */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return rc; +} + +/* TPM_KeyHandleEntries_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_KeyHandleEntries_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + printf(" TPM_KeyHandleEntries_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_KEY_HANDLES ; (*index)++) { + if (tpm_key_handle_entries[*index].key == NULL) { /* if the index is empty */ + printf(" TPM_KeyHandleEntries_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_KeyHandleEntries_GetSpace() returns the number of unused key handle entries. + +*/ + +void TPM_KeyHandleEntries_GetSpace(uint32_t *space, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint32_t i; + + printf(" TPM_KeyHandleEntries_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + (*space)++; + } + } + return; +} + +/* TPM_KeyHandleEntries_IsEvictSpace() returns 'isSpace' TRUE if there are at least 'minSpace' + entries that do not have the ownerEvict bit set, FALSE if not. +*/ + +void TPM_KeyHandleEntries_IsEvictSpace(TPM_BOOL *isSpace, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t minSpace) +{ + uint32_t evictSpace; + uint32_t i; + + for (i = 0, evictSpace = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + evictSpace++; + } + else { /* is index is used */ + if (!(tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + evictSpace++; /* space that can be evicted */ + } + } + } + printf(" TPM_KeyHandleEntries_IsEvictSpace: evictable space, minimum %u free %u\n", + minSpace, evictSpace); + if (evictSpace >= minSpace) { + *isSpace = TRUE; + } + else { + *isSpace = FALSE; + } + return; +} + +/* TPM_KeyHandleEntries_AddKeyEntry() adds a TPM_KEY object to the list. + + If *tpm_key_handle == 0, a value is assigned. If *tpm_key_handle != 0, + that value is used if it it not currently in use. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddKeyEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* in */ + TPM_KEY *tpm_key, + TPM_BOOL parentPCRStatus, + TPM_KEY_CONTROL keyControl) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_AddKeyEntry:\n"); + tpm_key_handle_entry.key = tpm_key; + tpm_key_handle_entry.parentPCRStatus = parentPCRStatus; + tpm_key_handle_entry.keyControl = keyControl; + rc = TPM_KeyHandleEntries_AddEntry(tpm_key_handle, + FALSE, /* don't have to keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + return rc; +} + +/* TPM_KeyHandleEntries_AddEntry() adds (copies) the TPM_KEY_HANDLE_ENTRY object to the list. + + If *tpm_key_handle == 0: + a value is assigned. + + If *tpm_key_handle != 0: + + If keepHandle is TRUE, the handle must be used. An error is returned if the handle is + already in use. + + If keepHandle is FALSE, if the handle is already in use, a new value is assigned. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) /* input */ + +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_KeyHandleEntries_AddEntry: handle %08x, keepHandle %u\n", + *tpm_key_handle, keepHandle); + /* check for valid TPM_KEY */ + if (rc == 0) { + if (tpm_key_handle_entry->key == NULL) { /* should never occur */ + printf("TPM_KeyHandleEntries_AddEntry: Error (fatal), NULL TPM_KEY\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entries); + if (!isSpace) { + printf("TPM_KeyHandleEntries_AddEntry: Error, key handle entries full\n"); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_key_handle, /* I/O */ + tpm_key_handle_entries, /* handle array */ + keepHandle, + TRUE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_KeyHandleEntries_GetEntry); + } + if (rc == 0) { + tpm_key_handle_entries[index].handle = *tpm_key_handle; + tpm_key_handle_entries[index].key = tpm_key_handle_entry->key; + tpm_key_handle_entries[index].keyControl = tpm_key_handle_entry->keyControl; + tpm_key_handle_entries[index].parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + printf(" TPM_KeyHandleEntries_AddEntry: Index %u key handle %08x key pointer %p\n", + index, tpm_key_handle_entries[index].handle, tpm_key_handle_entries[index].key); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetEntry() searches all entries for the entry matching the handle, and + returns that entry */ + +TPM_RESULT TPM_KeyHandleEntries_GetEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_KeyHandleEntries_GetEntry: Get entry for handle %08x\n", tpm_key_handle); + for (i = 0, found = FALSE ; (i < TPM_KEY_HANDLES) && !found ; i++) { + /* first test for matching handle. Then check for non-NULL to insure that entry is valid */ + if ((tpm_key_handle_entries[i].handle == tpm_key_handle) && + tpm_key_handle_entries[i].key != NULL) { /* found */ + found = TRUE; + *tpm_key_handle_entry = &(tpm_key_handle_entries[i]); + } + } + if (!found) { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x not found\n", tpm_key_handle); + rc = TPM_INVALID_KEYHANDLE; + } + else { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x found\n", tpm_key_handle); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetNextEntry() gets the next valid TPM_KEY_HANDLE_ENTRY at or after the + 'start' index. + + The current position is returned in 'current'. For iteration, the next 'start' should be + 'current' + 1. + + Returns + + 0 on success. + Returns TPM_RETRY when no more valid entries are found. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetNextEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + size_t *current, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + size_t start) +{ + TPM_RESULT rc = TPM_RETRY; + + printf(" TPM_KeyHandleEntries_GetNextEntry: Start %lu\n", (unsigned long)start); + for (*current = start ; *current < TPM_KEY_HANDLES ; (*current)++) { + if (tpm_key_handle_entries[*current].key != NULL) { + *tpm_key_handle_entry = &(tpm_key_handle_entries[*current]); + rc = 0; /* found an entry */ + break; + } + } + return rc; +} + +/* TPM_KeyHandleEntries_GetKey() gets the TPM_KEY associated with the handle. + + If the key has PCR usage (size is non-zero and one or more mask bits are set), PCR's have been + specified. It computes a PCR digest based on the TPM PCR's and verifies it against the key + digestAtRelease. + + Exceptions: readOnly is TRUE when the caller is indicating that only the public key is being read + (e.g. TPM_GetPubKey). In this case, if keyFlags TPM_PCRIGNOREDONREAD is also TRUE, the PCR + digest and locality must not be checked. + + If ignorePCRs is TRUE, the PCR digest is also ignored. A typical case is during OSAP and DSAP + session setup. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetKey(TPM_KEY **tpm_key, + TPM_BOOL *parentPCRStatus, + tpm_state_t *tpm_state, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL readOnly, + TPM_BOOL ignorePCRs, + TPM_BOOL allowEK) +{ + TPM_RESULT rc = 0; + TPM_BOOL found = FALSE; /* found a special handle key */ + TPM_BOOL validatePcrs = TRUE; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_GetKey: For handle %08x\n", tpm_key_handle); + /* If it's one of the special handles, return the TPM_KEY */ + if (rc == 0) { + switch (tpm_key_handle) { + case TPM_KH_SRK: /* The handle points to the SRK */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + *tpm_key = &(tpm_state->tpm_permanent_data.srk); + *parentPCRStatus = FALSE; /* storage root key (SRK) has no parent */ + found = TRUE; + } + else { + printf(" TPM_KeyHandleEntries_GetKey: Error, SRK handle with no owner\n"); + rc = TPM_KEYNOTFOUND; + } + break; + case TPM_KH_EK: /* The handle points to the PUBEK, only usable with + TPM_OwnerReadInternalPub */ + if (rc == 0) { + if (!allowEK) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle not allowed\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == + TPM_KEY_UNINITIALIZED) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle but no EK\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + *tpm_key = &(tpm_state->tpm_permanent_data.endorsementKey); + *parentPCRStatus = FALSE; /* endorsement key (EK) has no parent */ + found = TRUE; + } + break; + case TPM_KH_OWNER: /* handle points to the TPM Owner */ + case TPM_KH_REVOKE: /* handle points to the RevokeTrust value */ + case TPM_KH_TRANSPORT: /* handle points to the EstablishTransport static authorization */ + case TPM_KH_OPERATOR: /* handle points to the Operator auth */ + case TPM_KH_ADMIN: /* handle points to the delegation administration auth */ + printf("TPM_KeyHandleEntries_GetKey: Error, Unsupported key handle %08x\n", + tpm_key_handle); + rc = TPM_INVALID_RESOURCE; + break; + default: + /* continue searching */ + break; + } + } + /* If not one of the special key handles, search for the handle in the list */ + if ((rc == 0) && !found) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_GetKey: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* Part 1 25.1 Validate Key for use + 2. Set LK to the loaded key that is being used */ + /* NOTE: For special handle keys, this was already done. Just do here for keys in table */ + if ((rc == 0) && !found) { + *tpm_key = tpm_key_handle_entry->key; + *parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + } + /* 3. If LK -> pcrInfoSize is not 0 - if the key specifies PCR's */ + /* NOTE Done by TPM_Key_CheckPCRDigest() */ + /* a. If LK -> pcrInfo -> releasePCRSelection identifies the use of one or more PCR */ + if (rc == 0) { +#ifdef TPM_V12 + validatePcrs = !ignorePCRs && + !(readOnly && ((*tpm_key)->keyFlags & TPM_PCRIGNOREDONREAD)); +#else + validatePcrs = !ignorePCRs && !readOnly; +#endif + } + if ((rc == 0) && validatePcrs) { + if (rc == 0) { + rc = TPM_Key_CheckPCRDigest(*tpm_key, tpm_state); + } + } + return rc; +} + +/* TPM_KeyHandleEntries_SetParentPCRStatus() updates the parentPCRStatus member of the + TPM_KEY_HANDLE_ENTRY */ + +TPM_RESULT TPM_KeyHandleEntries_SetParentPCRStatus(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL parentPCRStatus) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_SetParentPCRStatus: Handle %08x\n", tpm_key_handle); + /* get the entry for the handle from the table */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_SetParentPCRStatus: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + if (rc == 0) { + tpm_key_handle_entry->parentPCRStatus = parentPCRStatus; + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictLoad() loads all owner evict keys from the stream into the key + handle entries table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictLoad(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t keyCount; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; /* each entry as read from the stream */ + TPM_TAG ownerEvictVersion; + + printf(" TPM_KeyHandleEntries_OwnerEvictLoad:\n"); + /* get the owner evict version number */ + if (rc == 0) { + rc = TPM_Load16(&ownerEvictVersion, stream, stream_size); + } + if (rc == 0) { + if (ownerEvictVersion != TPM_TAG_NVSTATE_OE_V1) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: " + "Error (fatal) unsupported version tag %04x\n", + ownerEvictVersion); + rc = TPM_FAIL; + } + } + /* get the count of owner evict keys in the stream */ + if (rc == 0) { + rc = TPM_Load16(&keyCount, stream, stream_size); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Count %hu\n", keyCount); + } + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* Must init each time through. This just resets the structure members. It does not free + the key that is in the structure after the first time through. That key has been added + (copied) to the key handle entries array. */ + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Loading key %hu\n", i); + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + if (rc == 0) { + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + /* add the entry to the list */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictStore() stores all owner evict keys from the key handle entries + table to the stream. + + It is used to serialize to NVRAM. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictStore(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t count; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictStore:\n"); + /* append the owner evict version number to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_OE_V1); + } + /* count the number of owner evict keys */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictGetCount(&count, tpm_key_handle_entries); + } + /* append the count to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, count); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + /* store it */ + rc = TPM_KeyHandleEntry_Store(sbuffer, &(tpm_key_handle_entries[i])); + } + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictGetCount returns the number of owner evict key entries + */ + +TPM_RESULT +TPM_KeyHandleEntries_OwnerEvictGetCount(uint16_t *count, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount:\n"); + /* count the number of loaded owner evict handles */ + if (rc == 0) { + for (i = 0 , *count = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + (*count)++; /* count it */ + } + } + } + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount: Count %hu\n", *count); + } + /* sanity check */ + if (rc == 0) { + if (*count > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictGetCount: Error (fatal), " + "count greater that max %u\n", TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictDelete() flushes owner evict keys. It does NOT write to NV. + +*/ + +void TPM_KeyHandleEntries_OwnerEvictDelete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + } + } + return; +} + +/* + Processing Functions +*/ + +/* 14.4 TPM_ReadPubek rev 99 + + Return the endorsement key public portion. This value should have controls placed upon access as + it is a privacy sensitive value + + The readPubek flag is set to FALSE by TPM_TakeOwnership and set to TRUE by TPM_OwnerClear, thus + mirroring if a TPM Owner is present. +*/ + +TPM_RESULT TPM_Process_ReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_NONCE antiReplay; + + /* processing */ + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; + TPM_DIGEST checksum; + + printf("TPM_Process_ReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_ReadPubek: antiReplay", antiReplay); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If TPM_PERMANENT_FLAGS -> readPubek is FALSE return TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: readPubek %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + if (!tpm_state->tpm_permanent_flags.readPubek) { + printf("TPM_Process_ReadPubek: Error, readPubek is FALSE\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. If no EK is present the TPM MUST return TPM_NO_ENDORSEMENT */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == TPM_KEY_UNINITIALIZED) { + printf("TPM_Process_ReadPubek: Error, no EK is present\n"); + returnCode = TPM_NO_ENDORSEMENT; + } + } + /* 3. Create checksum by performing SHA-1 on the concatenation of (pubEndorsementKey || + antiReplay). */ + if (returnCode == TPM_SUCCESS) { + /* serialize the TPM_PUBKEY components of the EK */ + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: pubEndorsementKey length %u\n", + pubEndorsementKeyStreamLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, +#if 0 /* The old Atmel chip and the LTC test code assume this, but it is incorrect */ + tpm_state->tpm_permanent_data.endorsementKey.pubKey.keyLength, + tpm_state->tpm_permanent_data.endorsementKey.pubKey.key, +#else /* this meets the TPM 1.2 standard */ + pubEndorsementKeyStreamLength, pubEndorsementKeyStreamBuffer, +#endif + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadPubek: 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) { + /* 4. Export the PUBEK and checksum. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append pubEndorsementKey */ + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 14.2 TPM_CreateRevocableEK rev 98 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. The TPM vendor may have a separate mechanism to create the EK and "squirt" the + value into the TPM. +*/ + +TPM_RESULT TPM_Process_CreateRevocableEK(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_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + TPM_BOOL generateReset = FALSE; /* If TRUE use TPM RNG to generate EKreset. If FALSE + use the passed value inputEKreset */ + TPM_NONCE inputEKreset; /* The authorization value to be used with TPM_RevokeTrust + if generateReset==FALSE, else the parameter is present + but unused */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_KEY *endorsementKey; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back NV */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateRevocableEK: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* get generateReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&generateReset, &command, ¶mSize); + } + /* get inputEKreset parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateRevocableEK: generateReset %02x\n", generateReset); + /* an email clarification says that this parameter is still present (but ignored) if + generateReset is TRUE */ + returnCode = TPM_Nonce_Load(inputEKreset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateRevocableEK: inputEKreset", inputEKreset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateRevocableEK: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + /* 2. Perform the actions of TPM_CreateEndorsementKeyPair, if any errors return with error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + if (returnCode == TPM_SUCCESS) { + /* 3. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to TRUE */ + TPM_SetCapability_Flag(&writeAllNV1, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + TRUE); /* value */ + /* a. If generateReset is TRUE then */ + if (generateReset) { + /* i. Set TPM_PERMANENT_DATA -> EKreset to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_permanent_data.EKReset); + } + /* b. Else */ + else { + /* i. Set TPM_PERMANENT_DATA -> EKreset to inputEkreset */ + TPM_Nonce_Copy(tpm_state->tpm_permanent_data.EKReset, inputEKreset); + } + } + /* save the permanent data and flags structure sto NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateRevocableEK: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 4. Return PUBEK, checksum and Ekreset */ + /* append pubEndorsementKey. */ + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + } + /* append outputEKreset */ + /* 5. The outputEKreset authorization is sent in the clear. There is no uniqueness on the + TPM available to actually perform encryption or use an encrypted channel. The assumption + is that this operation is occurring in a controlled environment and sending the value in + the clear is acceptable. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, tpm_state->tpm_permanent_data.EKReset); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* 14.1 TPM_CreateEndorsementKeyPair rev 104 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. +*/ + +TPM_RESULT TPM_Process_CreateEndorsementKeyPair(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ + TPM_KEY *endorsementKey = FALSE; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateEndorsementKeyPair: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateEndorsementKeyPair: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + /* 10. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to FALSE */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + FALSE); /* value */ + } + /* save the permanent data and flags structures to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateEndorsementKeyPair: 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) { + /* append pubEndorsementKey. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* TPM_CreateEndorsementKeyPair_Common rev 104 + + Actions common to TPM_CreateEndorsementKeyPair and TPM_CreateRevocableEK + + 'endorsementKey' points to TPM_PERMANENT_DATA -> endorsementKey +*/ + +TPM_RESULT TPM_CreateEndorsementKeyPair_Common(TPM_KEY *endorsementKey, /* output */ + TPM_PUBKEY *pubEndorsementKey, /* output */ + TPM_DIGEST checksum, /* output */ + TPM_BOOL *writePermanentData, /* output */ + tpm_state_t *tpm_state, /* input */ + TPM_KEY_PARMS *keyInfo, /* input */ + TPM_NONCE antiReplay) /* input */ +{ + TPM_RESULT returnCode = TPM_SUCCESS; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* from keyInfo */ + TPM_STORE_BUFFER pubEndorsementKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubEndorsementKeyBuffer; + uint32_t pubEndorsementKeyLength; + + printf("TPM_CreateEndorsementKeyPair_Common:\n"); + TPM_Sbuffer_Init(&pubEndorsementKeySerial); /* freed @1 */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + if (endorsementKey->keyUsage != TPM_KEY_UNINITIALIZED) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, key already initialized\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. Validate the keyInfo parameters for the key description */ + if (returnCode == TPM_SUCCESS) { + /* + RSA + */ + /* a. If the algorithm type is RSA the key length MUST be a minimum of + 2048. For interoperability the key length SHOULD be 2048 */ + if (keyInfo->algorithmID == TPM_ALG_RSA) { + if (returnCode == TPM_SUCCESS) { + /* get the keyInfo TPM_RSA_KEY_PARMS structure */ + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->keyLength != TPM_KEY_RSA_NUMBITS) { /* in bits */ + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad keyLength should be %u, was %u\n", + TPM_KEY_RSA_NUMBITS, tpm_rsa_key_parms->keyLength); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* kgold - Support only 2 primes */ + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad numPrimes should be 2, was %u\n", + tpm_rsa_key_parms->numPrimes); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* + not RSA + */ + /* b. If the algorithm type is other than RSA the strength provided by + the key MUST be comparable to RSA 2048 */ + else { + if (returnCode == TPM_SUCCESS) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "algorithmID %08x not supported\n", + keyInfo->algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* c. The other parameters of keyInfo (encScheme, sigScheme, etc.) are ignored. + */ + /* 3. Create a key pair called the "endorsement key pair" using a TPM-protected capability. The + type and size of key are that indicated by keyInfo. Set encScheme to + TPM_ES_RSAESOAEP_SHA1_MGF1. + + Save the endorsement key in permanent structure. Save the endorsement private key 'd' in the + TPM_KEY structure as encData */ + /* Certain HW TPMs do not ignore the encScheme parameter, and expect it to be + TPM_ES_RSAESOAEP_SHA1_MGF1. Test the value here to detect an application program that will + fail with that TPM. */ + + if (returnCode == TPM_SUCCESS) { + if (keyInfo->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + returnCode = TPM_BAD_KEY_PROPERTY; + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "encScheme %08x must be TPM_ES_RSAESOAEP_SHA1_MGF1\n", + keyInfo->encScheme); + } + } + if (returnCode == TPM_SUCCESS) { + keyInfo->sigScheme = TPM_ES_NONE; + returnCode = TPM_Key_GenerateRSA(endorsementKey, + tpm_state, + NULL, /* parent key, indicate root key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + 1, /* TPM_KEY */ + TPM_KEY_STORAGE, /* keyUsage */ + 0, /* keyFlags */ + TPM_AUTH_ALWAYS, /* authDataUsage */ + keyInfo, + NULL, /* no PCR's */ + NULL); /* no PCR's */ + *writePermanentData = TRUE; + } + /* Assemble the TPM_PUBKEY pubEndorsementKey for the response */ + if (returnCode == TPM_SUCCESS) { + /* add TPM_KEY_PARMS algorithmParms */ + returnCode = TPM_KeyParms_Copy(&(pubEndorsementKey->algorithmParms), + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + /* add TPM_SIZED_BUFFER pubKey */ + returnCode = TPM_SizedBuffer_Set(&(pubEndorsementKey->pubKey), + endorsementKey->pubKey.size, + endorsementKey->pubKey.buffer); + } + /* 4. Create checksum by performing SHA-1 on the concatenation of (PUBEK + || antiReplay) */ + if (returnCode == TPM_SUCCESS) { + /* serialize the pubEndorsementKey */ + returnCode = TPM_Pubkey_Store(&pubEndorsementKeySerial, + pubEndorsementKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubEndorsementKeySerial, + &pubEndorsementKeyBuffer, &pubEndorsementKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubEndorsementKeyLength, pubEndorsementKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* 5. Store the PRIVEK */ + /* NOTE Created in TPM_PERMANENT_DATA, call should save to NVRAM */ + /* 6. Create TPM_PERMANENT_DATA -> tpmDAASeed from the TPM RNG */ + /* 7. Create TPM_PERMANENT_DATA -> daaProof from the TPM RNG */ + /* 8. Create TPM_PERMANENT_DATA -> daaBlobKey from the TPM RNG */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + /* 9. Set TPM_PERMANENT_FLAGS -> CEKPUsed to TRUE */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_permanent_flags.CEKPUsed = TRUE; + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeySerial); /* @1 */ + return returnCode; +} + +/* 14.3 TPM_RevokeTrust rev 98 + + This command clears the EK and sets the TPM back to a pure default state. The generation of the + AuthData value occurs during the generation of the EK. It is the responsibility of the EK + generator to properly protect and disseminate the RevokeTrust AuthData. +*/ + +TPM_RESULT TPM_Process_RevokeTrust(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_NONCE EKReset; /* The value that will be matched to EK Reset */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + TPM_BOOL writeAllNV3 = FALSE; /* flags to write back flags */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_RevokeTrust: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get EKReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(EKReset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_RevokeTrust: EKReset", EKReset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_RevokeTrust: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM MUST validate that TPM_PERMANENT_FLAGS -> enableRevokeEK is TRUE, return + TPM_PERMANENTEK on error */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.enableRevokeEK) { + printf("TPM_Process_RevokeTrust: Error, enableRevokeEK is FALSE\n"); + returnCode = TPM_PERMANENTEK; + } + } + /* 2. The TPM MUST validate that the EKReset matches TPM_PERMANENT_DATA -> EKReset, return + TPM_AUTHFAIL on error. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Compare(tpm_state->tpm_permanent_data.EKReset, EKReset); + if (returnCode != 0) { + printf("TPM_Process_RevokeTrust: Error, EKReset mismatch\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. Ensure that physical presence is being asserted */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_RevokeTrust: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 4. Perform the actions of TPM_OwnerClear (excepting the command authentication) */ + /* a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This changes the + TPM_OwnerClear handling of the same NV areas */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + TRUE); /* delete all NVRAM */ + writeAllNV1 = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to FALSE */ + TPM_SetCapability_Flag(&writeAllNV2, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.nvLocked), /* flag */ + FALSE); /* value */ + /* 5. Invalidate TPM_PERMANENT_DATA -> tpmDAASeed */ + /* 6. Invalidate TPM_PERMANENT_DATA -> daaProof */ + /* 7. Invalidate TPM_PERMANENT_DATA -> daaBlobKey */ + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + if (returnCode == TPM_SUCCESS) { + /* 8. Invalidate the EK and any internal state associated with the EK */ + printf("TPM_Process_RevokeTrust: Deleting endorsement key\n"); + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.endorsementKey)); + TPM_SetCapability_Flag(&writeAllNV3, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.CEKPUsed), /* flag */ + FALSE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV1, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_RevokeTrust: 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 27.7 TPM_DisablePubekRead rev 94 + + The TPM Owner may wish to prevent any entity from reading the PUBEK. This command sets the + non-volatile flag so that the TPM_ReadPubek command always returns TPM_DISABLED_CMD. + + This commands has in essence been deprecated as TPM_TakeOwnership now sets the value to false. + The commands remains at this time for backward compatibility. +*/ + +TPM_RESULT TPM_Process_DisablePubekRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing */ + 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; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisablePubekRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisablePubekRead: 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 + */ + /* Verify that the TPM Owner authorizes the command and all of the input, on error return + TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 1. This capability sets the TPM_PERMANENT_FLAGS -> readPubek flag to FALSE. */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.readPubek), /* flag */ + FALSE); /* value */ + printf("TPM_Process_DisablePubekRead: readPubek now %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + /* save the permanent flags structure to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisablePubekRead: 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) { + /* no outParam's, set authorization response data */ + 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, 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); + } + return rcf; +} + +/* 27.6 TPM_OwnerReadPubek rev 94 + + Return the endorsement key public portion. This is authorized by the TPM Owner. +*/ + +TPM_RESULT TPM_Process_OwnerReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; /* The public endorsement key */ + + printf("TPM_Process_OwnerReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner authorization to execute this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* serialize the TPM_PUBKEY components of the EK */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadPubek: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Export the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* 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) { + /* no outParam's, set authorization response data */ + 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, 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_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 27.1.1 TPM_EvictKey rev 87 + + The key commands are deprecated as the new way to handle keys is to use the standard context + commands. So TPM_EvictKey is now handled by TPM_FlushSpecific, TPM_TerminateHandle by + TPM_FlushSpecific. + + The TPM will invalidate the key stored in the specified handle and return the space to the + available internal pool for subsequent query by TPM_GetCapability and usage by TPM_LoadKey. If + the specified key handle does not correspond to a valid key, an error will be returned. +*/ + +TPM_RESULT TPM_Process_EvictKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + 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 evictHandle; /* The handle of the key to be evicted. */ + + /* 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_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* table entry for the evictHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_EvictKey: Ordinal Entry\n"); + /* + get inputs + */ + /* get evictHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&evictHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_EvictKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* New 1.2 functionality + The command must check the status of the ownerEvict flag for the key and if the flag is TRUE + return TPM_KEY_CONTROL_OWNER + */ + /* evict the key stored in the specified handle */ + /* get the TPM_KEY_HANDLE_ENTRY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Evicting handle %08x\n", evictHandle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + evictHandle); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Error, key handle %08x not found\n", + evictHandle); + } + } + /* If tpm_key_handle_entry -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_EvictKey: Error, keyHandle specifies owner evict\n"); + returnCode = TPM_KEY_OWNER_CONTROL; + } + } + /* delete the entry, delete the key structure, and free the key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_EvictKey: 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 */ + } + /* 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); + } + return rcf; +} + +/* 14.5 TPM_OwnerReadInternalPub rev 87 + + A TPM Owner authorized command that returns the public portion of the EK or SRK. + + The keyHandle parameter is included in the incoming session authorization to prevent + alteration of the value, causing a different key to be read. Unlike most key handles, which + can be mapped by higher layer software, this key handle has only two fixed values. + +*/ + +TPM_RESULT TPM_Process_OwnerReadInternalPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters */ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle for either PUBEK or SRK */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *readKey = NULL; /* key to be read back */ + const unsigned char *stream; + uint32_t stream_size; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerReadInternalPub: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + /* NOTE: This is a special case, where the keyHandle is part of the HMAC calculation to + avoid a man-in-the-middle privacy attack that replaces the SRK handle with the EK + handle. */ + inParamStart = command; + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OwnerReadInternalPub: keyHandle %08x\n", keyHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadInternalPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the parameters and TPM Owner AuthData for this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 2. If keyHandle is TPM_KH_EK */ + if (keyHandle == TPM_KH_EK) { + /* a. Set publicPortion to PUBEK */ + printf("TPM_Process_OwnerReadInternalPub: Reading EK\n"); + readKey = &(tpm_state->tpm_permanent_data.endorsementKey); + } + /* 3. Else If keyHandle is TPM_KH_SRK */ + else if (keyHandle == TPM_KH_SRK) { + /* a. Set publicPortion to the TPM_PUBKEY of the SRK */ + printf("TPM_Process_OwnerReadInternalPub: Reading SRK\n"); + readKey = &(tpm_state->tpm_permanent_data.srk); + } + /* 4. Else return TPM_BAD_PARAMETER */ + else { + printf("TPM_Process_OwnerReadInternalPub: Error, invalid keyHandle %08x\n", + keyHandle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadInternalPub: 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; + /* 5. Export the public key of the referenced key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(response, &stream, &stream_size, readKey); + } + /* 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) { + /* no outParam's, set authorization response data */ + 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, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + + diff --git a/src/tpm12/tpm_key.h b/src/tpm12/tpm_key.h new file mode 100644 index 0000000..627233e --- /dev/null +++ b/src/tpm12/tpm_key.h @@ -0,0 +1,457 @@ +/********************************************************************************/ +/* */ +/* Key Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_key.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_KEY_H +#define TPM_KEY_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +#define TPM_KEY_RSA_NUMBITS 2048 + +extern unsigned char tpm_default_rsa_exponent[]; + +/* TPM_KEY */ + +void TPM_Key_Init(TPM_KEY *tpm_key); +void TPM_Key_InitTag12(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_Load(TPM_KEY *tpm_key, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_LoadPubData(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_LoadClear(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_StorePubData(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_StoreClear(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key); + +void TPM_Key_Delete(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_CheckStruct(int *ver, TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_Set(TPM_KEY *tpm_key, + tpm_state_t *tpm_state, + TPM_KEY *parent_key, + TPM_DIGEST *tpm_pcrs, + int ver, + TPM_KEY_USAGE keyUsage, + TPM_KEY_FLAGS keyFlags, + TPM_AUTH_DATA_USAGE authDataUsage, + TPM_KEY_PARMS *tpm_key_parms, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + uint32_t keyLength, + BYTE* publicKey, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +TPM_RESULT TPM_Key_Copy(TPM_KEY *tpm_key_dest, + TPM_KEY *tpm_key_src, + TPM_BOOL copyEncData); +TPM_RESULT TPM_Key_LoadStoreAsymKey(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_StorePubkey(TPM_STORE_BUFFER *pubkeyStream, + const unsigned char **pubkKeyStreamBuffer, + uint32_t *pubkeyStreamLength, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GenerateRSA(TPM_KEY *tpm_key, + tpm_state_t *tpm_state, + TPM_KEY *parent_key, + TPM_DIGEST *tpm_pcrs, + int ver, + TPM_KEY_USAGE keyUsage, + TPM_KEY_FLAGS keyFlags, + TPM_AUTH_DATA_USAGE authDataUsage, + TPM_KEY_PARMS *tpm_key_parms, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCR_INFO_LONG *tpm_pcr_info_long); + +TPM_RESULT TPM_Key_GeneratePubDataDigest(TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GeneratePubkeyDigest(TPM_DIGEST tpm_digest, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_ComparePubkey(TPM_KEY *tpm_key, + TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_Key_CheckPubDataDigest(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_GenerateEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key); +TPM_RESULT TPM_Key_DecryptEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key); + +TPM_RESULT TPM_Key_GetStoreAsymkey(TPM_STORE_ASYMKEY **tpm_store_asymkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetMigrateAsymkey(TPM_MIGRATE_ASYMKEY **tpm_migrate_asymkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetUsageAuth(TPM_SECRET **usageAuth, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPrivateKey(uint32_t *dbytes, + unsigned char **darr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_CheckProperties(int *ver, + TPM_KEY *tpm_key, + uint32_t keyLength, + TPM_BOOL FIPS); +TPM_RESULT TPM_Key_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_KEY *tpm_key, + size_t start_index); +TPM_RESULT TPM_Key_GetLocalityAtRelease(TPM_LOCALITY_SELECTION *localityAtRelease, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_CheckPCRDigest(TPM_KEY *tpm_key, + tpm_state_t *tpm_state); +TPM_RESULT TPM_Key_CheckRestrictDelegate(TPM_KEY *tpm_key, + TPM_CMK_DELEGATE restrictDelegate); + +/* + TPM_KEY_FLAGS +*/ + +TPM_RESULT TPM_KeyFlags_Load(TPM_KEY_FLAGS *tpm_key_flags, + unsigned char **stream, + uint32_t *stream_size); + +/* + TPM_KEY_PARMS +*/ + +void TPM_KeyParms_Init(TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_Set(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t parmSize, + BYTE* parms); +#if 0 +TPM_RESULT TPM_KeyParms_SetRSA(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t keyLength, + TPM_SIZED_BUFFER *exponent); +#endif +TPM_RESULT TPM_KeyParms_Copy(TPM_KEY_PARMS *tpm_key_parms_dest, + TPM_KEY_PARMS *tpm_key_parms_src); +TPM_RESULT TPM_KeyParms_Load(TPM_KEY_PARMS *tpm_key_parms, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyParms_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY_PARMS *tpm_key_parms); +void TPM_KeyParms_Delete(TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_GetRSAKeyParms(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms, + TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_CheckProperties(TPM_KEY_PARMS *tpm_key_parms, + TPM_KEY_USAGE tpm_key_usage, + uint32_t keyLength, + TPM_BOOL FIPS); +TPM_RESULT TPM_KeyParams_CheckDefaultExponent(TPM_SIZED_BUFFER *exponent); + +/* + TPM_PUBKEY +*/ + +void TPM_Pubkey_Init(TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_Pubkey_Load(TPM_PUBKEY *tpm_pubkey, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Pubkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PUBKEY *tpm_pubkey); +void TPM_Pubkey_Delete(TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_Pubkey_Set(TPM_PUBKEY *tpm_pubkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Pubkey_Copy(TPM_PUBKEY *dest_tpm_pubkey, + TPM_PUBKEY *src_tpm_pubkey); +TPM_RESULT TPM_Pubkey_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_Pubkey_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_PUBKEY *tpm_pubkey); + +/* + TPM_KEY_HANDLE_ENTRY +*/ + +void TPM_KeyHandleEntry_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +TPM_RESULT TPM_KeyHandleEntry_Load(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +void TPM_KeyHandleEntry_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +TPM_RESULT TPM_KeyHandleEntry_FlushSpecific(tpm_state_t *tpm_state, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +/* + TPM_KEY_HANDLE_ENTRY entries list +*/ + +void TPM_KeyHandleEntries_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +TPM_RESULT TPM_KeyHandleEntries_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntries_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_KeyHandleEntries_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +TPM_RESULT TPM_KeyHandleEntries_DeleteHandle(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle); + +void TPM_KeyHandleEntries_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_GetSpace(uint32_t *space, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_IsEvictSpace(TPM_BOOL *isSpace, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t minSpace); +TPM_RESULT TPM_KeyHandleEntries_AddKeyEntry(TPM_KEY_HANDLE *tpm_key_handle, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY *tpm_key, + TPM_BOOL parentPCRStatus, + TPM_KEY_CONTROL keyControl); +TPM_RESULT TPM_KeyHandleEntries_AddEntry(TPM_KEY_HANDLE *tpm_key_handle, + TPM_BOOL keepHandle, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +TPM_RESULT TPM_KeyHandleEntries_GetEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle); +TPM_RESULT TPM_KeyHandleEntries_GetKey(TPM_KEY **tpm_key, + TPM_BOOL *parentPCRStatus, + tpm_state_t *tpm_state, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL readOnly, + TPM_BOOL ignorePCRs, + TPM_BOOL allowEK); +TPM_RESULT TPM_KeyHandleEntries_SetParentPCRStatus(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL parentPCRStatus); +TPM_RESULT TPM_KeyHandleEntries_GetNextEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + size_t *current, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + size_t start); + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictLoad(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + unsigned char **stream, uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictStore(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictGetCount(uint16_t *count, + const TPM_KEY_HANDLE_ENTRY + *tpm_key_handle_entries); +void TPM_KeyHandleEntries_OwnerEvictDelete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +/* TPM_RSA_KEY_PARMS */ + +void TPM_RSAKeyParms_Init(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); +TPM_RESULT TPM_RSAKeyParms_Load(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_RSAKeyParms_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); +void TPM_RSAKeyParms_Delete(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); + +TPM_RESULT TPM_RSAKeyParms_Copy(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_dest, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_src); +TPM_RESULT TPM_RSAKeyParms_New(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms); +TPM_RESULT TPM_RSAKeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); + +/* TPM_STORE_ASYMKEY */ + +void TPM_StoreAsymkey_Init(TPM_STORE_ASYMKEY *tpm_store_asymkey); +TPM_RESULT TPM_StoreAsymkey_Load(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *tpm_store_pubkey); +TPM_RESULT TPM_StoreAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + const TPM_STORE_ASYMKEY *tpm_store_asymkey); +void TPM_StoreAsymkey_Delete(TPM_STORE_ASYMKEY *tpm_store_asymkey); + +TPM_RESULT TPM_StoreAsymkey_GenerateEncData(TPM_SIZED_BUFFER *encData, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY *parent_key); +TPM_RESULT TPM_StoreAsymkey_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_STORE_ASYMKEY *tpm_store_asymkey); +void TPM_StoreAsymkey_GetO1Size(uint32_t *o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey); +TPM_RESULT TPM_StoreAsymkey_CheckO1Size(uint32_t o1_size, + uint32_t k1k2_length); +TPM_RESULT TPM_StoreAsymkey_StoreO1(BYTE *o1, + uint32_t o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SECRET usageAuth); +TPM_RESULT TPM_StoreAsymkey_LoadO1(TPM_STORE_ASYMKEY *tpm_store_asymkey, + BYTE *o1, + uint32_t o1_size); + +/* TPM_MIGRATE_ASYMKEY */ + +void TPM_MigrateAsymkey_Init(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +TPM_RESULT TPM_MigrateAsymkey_Load(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_MigrateAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +void TPM_MigrateAsymkey_Delete(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); + +/* + TPM_STORE_PRIVKEY +*/ + +void TPM_StorePrivkey_Init(TPM_STORE_PRIVKEY *tpm_store_privkey); +TPM_RESULT TPM_StorePrivkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STORE_PRIVKEY *tpm_store_privkey); +void TPM_StorePrivkey_Delete(TPM_STORE_PRIVKEY *tpm_store_privkey); + +TPM_RESULT TPM_StorePrivkey_Convert(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *pubKey); + + +/* Command Processing Functions */ + + +TPM_RESULT TPM_Process_ReadPubek(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 TPM_Process_CreateRevocableEK(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 TPM_Process_CreateEndorsementKeyPair(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 TPM_CreateEndorsementKeyPair_Common(TPM_KEY *endorsementKey, + TPM_PUBKEY *pubEndorsementKey, + TPM_DIGEST checksum, + TPM_BOOL *writePermanentData, + tpm_state_t *tpm_state, + TPM_KEY_PARMS *keyInfo, + TPM_NONCE antiReplay); + +TPM_RESULT TPM_Process_RevokeTrust(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 TPM_Process_DisablePubekRead(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 TPM_Process_OwnerReadPubek(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 TPM_Process_EvictKey(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 TPM_Process_OwnerReadInternalPub(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); + +#endif diff --git a/src/tpm12/tpm_libtpms_io.c b/src/tpm12/tpm_libtpms_io.c new file mode 100644 index 0000000..dfb5646 --- /dev/null +++ b/src/tpm12/tpm_libtpms_io.c @@ -0,0 +1,70 @@ +/********************************************************************************/ +/* */ +/* Libtpms IO Init */ +/* Written by Ken Goldman, Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_io.c 4564 2011-04-13 19:33:38Z stefanb $ */ +/* */ +/* (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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_platform.h" +#include "tpm_types.h" + +#include "tpm_library_intern.h" + +/* header for this file */ +#include "tpm_io.h" + +/* TPM_IO_Init initializes the TPM to host interface. + + This is the Unix platform dependent socket version. +*/ + +TPM_RESULT TPM_IO_Init(void) +{ + TPM_RESULT rc = 0; + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available */ + if (cbs->tpm_io_init) { + rc = cbs->tpm_io_init(); + return rc; + } else { + /* Below code would start a TCP server socket; we don't want this + but rather expect all commands via TPMLIB_Process() to be sent + to the TPM. */ + return TPM_SUCCESS; + } +} diff --git a/src/tpm12/tpm_load.c b/src/tpm12/tpm_load.c new file mode 100644 index 0000000..b534eee --- /dev/null +++ b/src/tpm12/tpm_load.c @@ -0,0 +1,309 @@ +/********************************************************************************/ +/* */ +/* Load from Stream Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_load.c 4668 2012-01-25 21:16:48Z 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. */ +/********************************************************************************/ + +/* Generally useful utilities to deserialize structures from a stream */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_sizedbuffer.h" +#include "tpm_types.h" + +#include "tpm_load.h" + +/* The LOADn() functions convert a big endian stream to integer types */ + +uint32_t LOAD32(const unsigned char *buffer, unsigned int offset) +{ + unsigned int i; + uint32_t result = 0; + + for (i = 0 ; i < 4 ; i++) { + result <<= 8; + result |= buffer[offset + i]; + } + return result; +} + +uint16_t LOAD16(const unsigned char *buffer, unsigned int offset) +{ + unsigned int i; + uint16_t result = 0; + + for (i = 0 ; i < 2 ; i++) { + result <<= 8; + result |= buffer[offset + i]; + } + return result; +} + +uint8_t LOAD8(const unsigned char *buffer, unsigned int offset) +{ + uint8_t result = 0; + + result |= buffer[offset]; + return result; +} + +/* TPM_Load32() loads 'tpm_uint32' from the stream. + + It checks that the stream has sufficient data, and adjusts 'stream' + and 'stream_size' past the data. +*/ + +TPM_RESULT TPM_Load32(uint32_t *tpm_uint32, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint32_t)) { + printf("TPM_Load32: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint32_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint32 = LOAD32(*stream, 0); + *stream += sizeof (uint32_t); + *stream_size -= sizeof (uint32_t); + } + return rc; +} + +/* TPM_Load16() loads 'tpm_uint16' from the stream. + + It checks that the stream has sufficient data, and adjusts 'stream' + and 'stream_size' past the data. +*/ + +TPM_RESULT TPM_Load16(uint16_t *tpm_uint16, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint16_t)) { + printf("TPM_Load16: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint16_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint16 = LOAD16(*stream, 0); + *stream += sizeof (uint16_t); + *stream_size -= sizeof (uint16_t); + } + return rc; +} + +TPM_RESULT TPM_Load8(uint8_t *tpm_uint8, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint8_t)) { + printf("TPM_Load8: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint8_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint8 = LOAD8(*stream, 0); + *stream += sizeof (uint8_t); + *stream_size -= sizeof (uint8_t); + } + return rc; +} + +/* Boolean incoming parameter values other than 0x00 and 0x01 have an implementation specific + interpretation. The TPM SHOULD return TPM_BAD_PARAMETER. +*/ + +TPM_RESULT TPM_LoadBool(TPM_BOOL *tpm_bool, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(TPM_BOOL)) { + printf("TPM_LoadBool: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(TPM_BOOL)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_bool = LOAD8(*stream, 0); + *stream += sizeof (uint8_t); + *stream_size -= sizeof (uint8_t); + } + if (rc == 0) { + if ((*tpm_bool != TRUE) && (*tpm_bool != FALSE)) { + printf("TPM_LoadBool: Error, illegal value %02x\n", *tpm_bool); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_Loadn() copies 'data_length' bytes from 'stream' to 'data' with + no endian adjustments. */ + +TPM_RESULT TPM_Loadn(BYTE *data, + size_t data_length, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < data_length) { + printf("TPM_Loadn: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)data_length); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + memcpy(data, *stream, data_length); + *stream += data_length; + *stream_size -= data_length; + } + return rc; +} + +/* TPM_LoadLong() creates a long from a stream in network byte order. + + The stream is not advanced. +*/ + +TPM_RESULT TPM_LoadLong(unsigned long *result, + const unsigned char *stream, + uint32_t stream_size) +{ + TPM_RESULT rc = 0; + size_t i; /* byte iterator */ + + printf(" TPM_LoadLong:\n"); + if (rc == 0) { + if (stream_size > sizeof(unsigned long)) { + printf(" TPM_LoadLong: Error, stream size %u too large\n", stream_size); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + *result = 0; /* initialize all bytes to 0 in case buffer is less than sizeof(unsigned + long) bytes */ + for (i = 0 ; i < stream_size ; i++) { + /* copy big endian stream, put lowest address in an upper byte, highest address in byte + 0 */ + *result |= (unsigned long)(((unsigned long)stream[i]) << ((stream_size - 1 - i) * 8)); + } + printf(" TPM_LoadLong: Result %08lx\n", *result); + } + return rc; +} + +#if 0 +/* TPM_LoadString() returns a pointer to a C string. It does not copy the string. + + */ + +TPM_RESULT TPM_LoadString(const char **name, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + char *ptr; + + *name = NULL; + /* search for the first nul character */ + if (rc == 0) { + ptr = memchr(*stream, (int)'\0', *stream_size); + if (ptr == NULL) { + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + *name = (char *)*stream; /* cast because converting binary to string */ + *stream_size -= (ptr - *name) + 1; + *stream = (unsigned char *)ptr + 1; + } + return rc; +} +#endif + +/* TPM_CheckTag() loads a TPM_STRUCTURE_TAG from 'stream'. It check that the value is 'expectedTag' + and returns TPM_INVALID_STRUCTURE on error. + +*/ + +TPM_RESULT TPM_CheckTag(TPM_STRUCTURE_TAG expectedTag, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_STRUCTURE_TAG tag; + + if (rc == 0) { + rc = TPM_Load16(&tag, stream, stream_size); + } + if (rc == 0) { + if (tag != expectedTag) { + printf("TPM_CheckTag: Error, tag expected %04x found %04hx\n", expectedTag, tag); + rc = TPM_INVALID_STRUCTURE; + } + } + return rc; +} + diff --git a/src/tpm12/tpm_load.h b/src/tpm12/tpm_load.h new file mode 100644 index 0000000..08336cd --- /dev/null +++ b/src/tpm12/tpm_load.h @@ -0,0 +1,80 @@ +/********************************************************************************/ +/* */ +/* Load from Stream Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_load.h 4668 2012-01-25 21:16:48Z 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. */ +/********************************************************************************/ + +#ifndef TPM_LOAD_H +#define TPM_LOAD_H + +#include "tpm_types.h" + +TPM_RESULT TPM_Load32(uint32_t *tpm_uint32, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Load16(uint16_t *tpm_uint16, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Load8(uint8_t *tpm_uint8, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Loadn(BYTE *data, + size_t data_length, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_LoadBool(TPM_BOOL *tpm_bool, + unsigned char **stream, + uint32_t *stream_size); + +TPM_RESULT TPM_LoadLong(unsigned long *result, + const unsigned char *stream, + uint32_t stream_size); +#if 0 +TPM_RESULT TPM_LoadString(const char **name, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_CheckTag(TPM_STRUCTURE_TAG expectedTag, + unsigned char **stream, + uint32_t *stream_size); + +/* byte stream to type */ + +uint32_t LOAD32(const unsigned char *buffer, unsigned int offset); +uint16_t LOAD16(const unsigned char *buffer, unsigned int offset); +uint8_t LOAD8(const unsigned char *buffer, unsigned int offset); + +#endif diff --git a/src/tpm12/tpm_maint.c b/src/tpm12/tpm_maint.c new file mode 100644 index 0000000..98753a2 --- /dev/null +++ b/src/tpm12/tpm_maint.c @@ -0,0 +1,1304 @@ +/********************************************************************************/ +/* */ +/* Maintenance Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_maint.c 4442 2011-02-14 20:20:01Z 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. */ +/********************************************************************************/ + +#if !defined(TPM_NOMAINTENANCE) && !defined(TPM_NOMAINTENANCE_COMMANDS) + +#include <stdio.h> +#include <stdlib.h> + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_owner.h" +#include "tpm_permanent.h" +#include "tpm_process.h" + +#include "tpm_maint.h" + +/* + Processing Functions +*/ + +/* 12. Maintenance Functions (optional) + + The maintenance mechanisms in the TPM MUST not require the TPM to hold a global secret. The + definition of global secret is a secret value shared by more than one TPM. + + The TPME is not allowed to pre-store or use unique identifiers in the TPM for the purpose of + maintenance. The TPM MUST NOT use the endorsement key for identification or encryption in the + maintenance process. The maintenance process MAY use a TPM Identity to deliver maintenance + information to specific TPM's. + + The maintenance process can only change the SRK, tpmProof and TPM Owner AuthData fields. + + The maintenance process can only access data in shielded locations where this data is necessary + to validate the TPM Owner, validate the TPME and manipulate the blob + + The TPM MUST be conformant to the TPM specification, protection profiles and security targets + after maintenance. The maintenance MAY NOT decrease the security values from the original + security target. + + The security target used to evaluate this TPM MUST include this command in the TOE. +*/ + +/* When a maintenance archive is created with generateRandom FALSE, the maintenance blob is XOR + encrypted with the owner authorization before encryption with the maintenance public key. This + prevents the manufacturer from obtaining plaintext data. The receiving TPM must have the same + owner authorization as the sending TPM in order to XOR decrypt the archive. + + When generateRandom is TRUE, the maintenance blob is XOR encrypted with random data, which is + also returned. This permits someone trusted by the Owner to load the maintenance archive into the + replacement platform in the absence of the Owner and manufacturer, without the Owner having to + reveal information about his auth value. The receiving and sending TPM's may have different owner + authorizations. The random data is transferred from the sending TPM owner to the receiving TPM + owner out of band, so the maintenance blob remains hidden from the manufacturer. + + This is a typical maintenance sequence: + 1. Manufacturer: + - generates maintenance key pair + - gives public key to TPM1 owner + 2. TPM1: TPM_LoadManuMaintPub + - load maintenance public key + 3. TPM1: TPM_CreateMaintenanceArchive + - XOR encrypt with owner auth or random + - encrypt with maintenance public key + 4. Manufacturer: + - decrypt with maintenance private key + - (still XOR encrypted with owner auth or random) + - encrypt with TPM2 SRK public key + 5. TPM2: TPM_LoadMaintenanceArchive + - decrypt with SRK private key + - XOR decrypt with owner auth or random +*/ + +/* 12.1 TPM_CreateMaintenanceArchive rev 101 + + This command creates the MaintenanceArchive. It can only be executed by the owner, and may be + shut off with the TPM_KillMaintenanceFeature command. +*/ + +TPM_RESULT TPM_Process_CreateMaintenanceArchive(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_BOOL generateRandom; /* Use RNG or Owner auth to generate 'random'. */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + uint32_t o1Oaep_size; + BYTE *o1Oaep; + BYTE *r1InnerWrapKey; + BYTE *x1InnerWrap; + TPM_KEY a1; /* SRK archive result */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* Random data to XOR with result. */ + TPM_STORE_BUFFER archive; /* Encrypted key archive. */ + + printf("TPM_Process_CreateMaintenanceArchive: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&random); /* freed @1 */ + TPM_Key_Init(&a1); /* freed @2 */ + TPM_Sbuffer_Init(&archive); /* freed @3 */ + o1Oaep = NULL; /* freed @4 */ + r1InnerWrapKey = NULL; /* freed @5 */ + x1InnerWrap = NULL; /* freed @6 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get generateRandom parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&generateRandom, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateMaintenanceArchive: 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 + */ + /* Upon authorization being confirmed this command does the following: */ + /* 1. Validates that the TPM_PERMANENT_FLAGS -> AllowMaintenance is TRUE. If it is FALSE, the + TPM SHALL return TPM_DISABLED_CMD and exit this capability. */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.allowMaintenance) { + printf("TPM_Process_CreateMaintenanceArchive: Error allowMaintenance FALSE\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. Validates the TPM Owner AuthData. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. If the value of TPM_PERMANENT_DATA -> ManuMaintPub is zero, the TPM MUST return the error + code TPM_KEYNOTFOUND */ + if (returnCode == TPM_SUCCESS) { + /* since there is no keyUsage, algorithmID seems like a way to check for an empty key */ + if (tpm_state->tpm_permanent_data.manuMaintPub.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CreateMaintenanceArchive: manuMaintPub key not found\n"); + returnCode = TPM_KEYNOTFOUND; + } + } + /* 4. Build a1 a TPM_KEY structure using the SRK. The encData field is not a normal + TPM_STORE_ASYMKEY structure but rather a TPM_MIGRATE_ASYMKEY structure built using the + following actions. */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Copy(&a1, + &(tpm_state->tpm_permanent_data.srk), + FALSE); /* don't copy encData */ + } + /* 5. Build a TPM_STORE_PRIVKEY structure from the SRK. This privKey element should be 132 bytes + long for a 2K RSA key. */ + /* 6. Create k1 and k2 by splitting the privKey element created in step 4 into 2 parts. k1 is + the first 20 bytes of privKey, k2 contains the remainder of privKey. */ + /* 7. Build m1 by creating and filling in a TPM_MIGRATE_ASYMKEY structure */ + /* a. m1 -> usageAuth is set to TPM_PERMANENT_DATA -> tpmProof */ + /* b. m1 -> pubDataDigest is set to the digest value of the SRK fields from step 4 */ + /* c. m1 -> payload is set to TPM_PT_MAINT */ + /* d. m1 -> partPrivKey is set to k2 */ + /* 8. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* a. m = TPM_MIGRATE_ASYMKEY structure (step 7) */ + /* b. pHash = TPM_PERMANENT_DATA -> ownerAuth */ + /* c. seed = s1 = k1 (step 6) */ + if (returnCode == TPM_SUCCESS) { + TPM_StoreAsymkey_GetO1Size(&o1Oaep_size, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&r1InnerWrapKey, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&x1InnerWrap, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StoreAsymkey_StoreO1 + (o1Oaep, + o1Oaep_size, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey, + tpm_state->tpm_permanent_data.ownerAuth, /* pHash */ + TPM_PT_MAINT, /* TPM_PAYLOAD_TYPE */ + tpm_state->tpm_permanent_data.tpmProof); /* usageAuth */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: o1 -", o1Oaep); + /* 9. If generateRandom = TRUE */ + if (generateRandom) { + /* a. Create r1 by obtaining values from the TPM RNG. The size of r1 MUST be the same + size as o1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Random(r1InnerWrapKey, o1Oaep_size); + } + /* Set random parameter to r1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&random, o1Oaep_size, r1InnerWrapKey); + } + } + /* 10. If generateRandom = FALSE */ + else { + /* a. Create r1 by applying MGF1 to the TPM Owner AuthData. The size of r1 MUST be the + same size as o1. */ + returnCode = TPM_MGF1(r1InnerWrapKey, /* unsigned char *mask */ + o1Oaep_size, /* long len */ + tpm_state->tpm_permanent_data.ownerAuth, /* const unsigned + char *seed */ + TPM_SECRET_SIZE); /* long seedlen */ + /* Set randomSize to 0. */ + /* NOTE Done by TPM_SizedBuffer_Init() */ + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: r1 -", r1InnerWrapKey); + /* 11. Create x1 by XOR of o1 with r1 */ + TPM_XOR(x1InnerWrap, o1Oaep, r1InnerWrapKey, o1Oaep_size); + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: x1", x1InnerWrap); + /* 12. Encrypt x1 with the manuMaintPub key using the TPM_ES_RSAESOAEP_SHA1_MGF1 + encryption scheme. NOTE The check for OAEP is done by TPM_LoadManuMaintPub */ + /* 13. Set a1 -> encData to the encryption of x1 */ + returnCode = TPM_RSAPublicEncrypt_Pubkey(&(a1.encData), + x1InnerWrap, + o1Oaep_size, + &(tpm_state->tpm_permanent_data.manuMaintPub)); + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: encData", a1.encData.buffer); + } + /* 14. Set TPM_PERMANENT_FLAGS -> maintenanceDone to TRUE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMaintenanceArchive: Set maintenanceDone\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.maintenanceDone), /* flag */ + TRUE); /* value */ + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* 15. Return a1 in the archive parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Store(&archive, &a1); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateMaintenanceArchive: 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 randomSize and random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return archiveSize and archive */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &archive); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&random); /* @1 */ + TPM_Key_Delete(&a1); /* @2 */ + TPM_Sbuffer_Delete(&archive); /* @3 */ + free(o1Oaep); /* @4 */ + free(r1InnerWrapKey); /* @5 */ + free(x1InnerWrap); /* @6 */ + return rcf; +} + +/* 12.2 TPM_LoadMaintenanceArchive rev 98 + + This command loads in a Maintenance archive that has been massaged by the manufacturer to load + into another TPM + + If the maintenance archive was created using the owner authorization for XOR encryption, the + current owner authorization must be used for decryption. The owner authorization does not change. + + If the maintenance archive was created using random data for the XOR encryption, the vendor + specific arguments must include the random data. The owner authorization may change. +*/ + +TPM_RESULT TPM_Process_LoadMaintenanceArchive(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_SIZED_BUFFER archive; /* Vendor specific arguments, from + TPM_CreateMaintenanceArchive */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth.*/ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_SECRET saveKey; /* copy of HMAC key, since key changes */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + unsigned char *stream; /* the input archive stream */ + uint32_t stream_size; + BYTE *x1InnerWrap; + uint32_t x1InnerWrap_size; + BYTE *r1InnerWrapKey; /* for XOR decryption */ + BYTE *o1Oaep; + TPM_KEY newSrk; + TPM_STORE_ASYMKEY srk_store_asymkey; + TPM_STORE_BUFFER asym_sbuffer; + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + /* Vendor specific arguments */ + + printf("TPM_Process_LoadMaintenanceArchive: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&archive); /* freed @1 */ + TPM_Key_Init(&newSrk); /* freed @2 */ + x1InnerWrap = NULL; /* freed @3 */ + r1InnerWrapKey = NULL; /* freed @4 */ + o1Oaep = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&srk_store_asymkey); /* freed @6 */ + TPM_Sbuffer_Init(&asym_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get Vendor specific arguments */ + if (returnCode == TPM_SUCCESS) { + /* NOTE TPM_CreateMaintenanceArchive sends a TPM_SIZED_BUFFER archive. */ + returnCode = TPM_SizedBuffer_Load(&archive, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadMaintenanceArchive: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner's AuthData */ + /* Upon authorization being confirmed this command does the following: */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that the maintenance information was sent by the TPME. The validation mechanism + MUST use a strength of function that is at least the same strength of function as a digital + signature performed using a 2048 bit RSA key. */ + /* NOTE SRK is 2048 bits minimum */ + /* 3. The packet MUST contain m2 as defined in Section 12.1 */ + /* The TPM_SIZED_BUFFER archive contains a TPM_KEY with a TPM_MIGRATE_ASYMKEY that will become + the new SRK */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Deserializing TPM_KEY parameter\n"); + stream = archive.buffer; + stream_size = archive.size; + returnCode = TPM_Key_Load(&newSrk, &stream, &stream_size); + } + /* decrypt the TPM_KEY -> encData to x1 using the current SRK */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Decrypting TPM_KEY -> encData with SRK\n"); + returnCode = TPM_RSAPrivateDecryptMalloc(&x1InnerWrap, + &x1InnerWrap_size, + newSrk.encData.buffer, + newSrk.encData.size, + &(tpm_state->tpm_permanent_data.srk)); + } + /* allocate memory for r1 based on x1 XOR encrypted data */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: x1", x1InnerWrap); + printf("TPM_Process_LoadMaintenanceArchive: x1 size %u\n", x1InnerWrap_size); + returnCode = TPM_Malloc(&r1InnerWrapKey, x1InnerWrap_size); + } + /* allocate memory for o1 based on x1 XOR encrypted data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, x1InnerWrap_size); + } + /* generate the XOR encryption secret from the ownerAuth */ + /* NOTE: This does not yet support a supplied random number as the inner wrapper key */ + if (returnCode == TPM_SUCCESS) { + TPM_MGF1(r1InnerWrapKey, /* unsigned char *mask */ + x1InnerWrap_size, /* long len */ + tpm_state->tpm_permanent_data.ownerAuth, /* const unsigned char *seed */ + TPM_SECRET_SIZE); /* long seedlen */ + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: r1 -", r1InnerWrapKey); + /* decrypt x1 to o1 using XOR encryption secret */ + printf("TPM_Process_LoadMaintenanceArchive: XOR Decrypting TPM_KEY SRK parameter\n"); + TPM_XOR(o1Oaep, x1InnerWrap, r1InnerWrapKey, x1InnerWrap_size); + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: o1 -", o1Oaep); + } + /* convert o1 to TPM_STORE_ASYMKEY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StoreAsymkey_LoadO1(&srk_store_asymkey, o1Oaep, x1InnerWrap_size); + } + /* TPM1 tpmProof comes in as TPM_STORE_ASYMKEY -> usageAuth */ + /* TPM1 ownerAuth comes in as TPM_STORE_ASYMKEY -> migrationAuth (from pHash) */ + /* 4. Ensure that only the target TPM can interpret the maintenance packet. The protection + mechanism MUST use a strength of function that is at least the same strength of function as a + digital signature performed using a 2048 bit RSA key. */ + /* 5. Execute the actions of TPM_OwnerClear. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't erase NVRAM with D bit set */ + writeAllNV1 = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* 6. Process the maintenance information */ + /* a. Update the SRK */ + /* i. Set the SRK usageAuth to be the same as the TPM source owner's AuthData */ + /* NOTE The source srk.usageAuth was lost, as usageAuth is used to transfer the tpmProof */ + TPM_Secret_Copy(srk_store_asymkey.usageAuth, srk_store_asymkey.migrationAuth); + /* b. Update TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(tpm_state->tpm_permanent_data.tpmProof, srk_store_asymkey.usageAuth); + /* save a copy of the HMAC key for the response before invalidating */ + TPM_Secret_Copy(saveKey, *hmacKey); + /* c. Update TPM_PERMANENT_DATA -> ownerAuth */ + TPM_Secret_Copy(tpm_state->tpm_permanent_data.ownerAuth, srk_store_asymkey.migrationAuth); + /* serialize the TPM_STORE_ASYMKEY object */ + returnCode = TPM_StoreAsymkey_Store(&asym_sbuffer, FALSE, &srk_store_asymkey); + } + /* copy back to the new srk encData (clear text for SRK) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(newSrk.encData), &asym_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* free old SRK resources */ + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.srk)); + /* Copy new SRK to TPM_PERMANENT_DATA -> srk */ + /* This copies the basic TPM_KEY, but not the TPM_STORE_ASYMKEY cache */ + returnCode = TPM_Key_Copy(&(tpm_state->tpm_permanent_data.srk), &newSrk, + TRUE); /* copy encData */ + } + /* Recreate the TPM_STORE_ASYMKEY cache */ + if (returnCode == TPM_SUCCESS) { + stream = newSrk.encData.buffer; + stream_size = newSrk.encData.size; + returnCode = TPM_Key_LoadStoreAsymKey(&(tpm_state->tpm_permanent_data.srk), FALSE, + &stream, &stream_size); + } + /* 7. Set TPM_PERMANENT_FLAGS -> maintenanceDone to TRUE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Set maintenanceDone\n"); + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.maintenanceDone), /* flag */ + TRUE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadMaintenanceArchive: 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, /* the original 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(&archive); /* @1 */ + TPM_Key_Delete(&newSrk); /* @2 */ + free(x1InnerWrap); /* @3 */ + free(r1InnerWrapKey); /* @4 */ + free(o1Oaep); /* @5 */ + TPM_StoreAsymkey_Delete(&srk_store_asymkey); /* @6 */ + TPM_Sbuffer_Delete(&asym_sbuffer); /* @7 */ + return rcf; +} + +/* 12.3 TPM_KillMaintenanceFeature rev 87 + + The KillMaintencanceFeature is a permanent action that prevents ANYONE from creating a + maintenance archive. This action, once taken, is permanent until a new TPM Owner is set. + + This action is to allow those customers who do not want the maintenance feature to not allow the + use of the maintenance feature. + + At the discretion of the Owner, it should be possible to kill the maintenance feature in such a + way that the only way to recover maintainability of the platform would be to wipe out the root + keys. This feature is mandatory in any TPM that implements the maintenance feature. +*/ + +TPM_RESULT TPM_Process_KillMaintenanceFeature(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_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth.*/ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_KillMaintenanceFeature: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_KillMaintenanceFeature: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner AuthData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Set the TPM_PERMANENT_FLAGS.allowMaintenance flag to FALSE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KillMaintenanceFeature: Clear allowMaintenance\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.allowMaintenance), /* flag */ + FALSE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_KillMaintenanceFeature: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 12.4 TPM_LoadManuMaintPub rev 96 + + The LoadManuMaintPub command loads the manufacturer's public key for use in the maintenance + process. The command installs ManuMaintPub in PERMANENT data storage inside a TPM. Maintenance + enables duplication of non-migratory data in protected storage. There is therefore a security + hole if a platform is shipped before the maintenance public key has been installed in a TPM. + + The command is expected to be used before installation of a TPM Owner or any key in TPM protected + storage. It therefore does not use authorization. + + The pubKey MUST specify an algorithm whose strength is not less than the RSA algorithm with 2048 + bit keys. + + pubKey SHOULD unambiguously identify the entity that will perform the maintenance process with + the TPM Owner. + + TPM_PERMANENT_DATA -> manuMaintPub SHALL exist in a TPM-shielded location, only. + + If an entity (Platform Entity) does not support the maintenance process but issues a platform + credential for a platform containing a TPM that supports the maintenance process, the value of + TPM_PERMANENT_DATA -> manuMaintPub MUST be set to zero before the platform leaves the entity's + control. +*/ + +TPM_RESULT TPM_Process_LoadManuMaintPub(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_NONCE antiReplay; /* AntiReplay and validation nonce */ + TPM_PUBKEY pubKey; /* The public key of the manufacturer to be in use for maintenance + */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ + TPM_STORE_BUFFER pubKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubKeyBuffer; + uint32_t pubKeyLength; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST checksum; /* Digest of pubKey and antiReplay */ + + printf("TPM_Process_LoadManuMaintPub: Ordinal Entry\n"); + TPM_Pubkey_Init(&pubKey); /* freed @1 */ + TPM_Sbuffer_Init(&pubKeySerial); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get pubKey parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadManuMaintPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* The first valid TPM_LoadManuMaintPub command received by a TPM SHALL */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_data.allowLoadMaintPub) { + printf("TPM_Process_LoadManuMaintPub: Error, command already run\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* The pubKey MUST specify an algorithm whose strength is not less than the RSA algorithm with + 2048 bit keys. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_CheckProperties(&(pubKey.algorithmParms), /* TPM_KEY_PARMS */ + TPM_KEY_STORAGE, /* TPM_KEY_USAGE */ + 2048, /* required, in bits */ + TRUE); /* FIPS */ + } + /* 1. Store the parameter pubKey as TPM_PERMANENT_DATA -> manuMaintPub. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Copy(&(tpm_state->tpm_permanent_data.manuMaintPub), + &pubKey); + writeAllNV = TRUE; + } + /* 2. Set checksum to SHA-1 of (pubkey || antiReplay) */ + if (returnCode == TPM_SUCCESS) { + /* serialize pubkey */ + returnCode = TPM_Pubkey_Store(&pubKeySerial, &pubKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubKeySerial, &pubKeyBuffer, &pubKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubKeyLength, pubKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* 4. Subsequent calls to TPM_LoadManuMaintPub SHALL return code TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_permanent_data.allowLoadMaintPub = FALSE; + } + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadManuMaintPub: 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; + /* 3. Export the checksum */ + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&pubKey); /* @1 */ + TPM_Sbuffer_Delete(&pubKeySerial); /* @2 */ + return rcf; +} + +/* 12.5 TPM_ReadManuMaintPub rev 99 + + The ReadManuMaintPub command is used to check whether the manufacturer's public maintenance key + in a TPM has the expected value. This may be useful during the manufacture process. The command + returns a digest of the installed key, rather than the key itself. This hinders discovery of the + maintenance key, which may (or may not) be useful for manufacturer privacy. + + The command is expected to be used before installation of a TPM Owner or any key in TPM protected + storage. It therefore does not use authorization. + + This command returns the hash of the antiReplay nonce and the previously loaded manufacturer's + maintenance public key. +*/ + +TPM_RESULT TPM_Process_ReadManuMaintPub(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_NONCE antiReplay; /* AntiReplay and validation nonce */ + + /* 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_STORE_BUFFER pubKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubKeyBuffer; + uint32_t pubKeyLength; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST checksum; /* Digest of pubKey and antiReplay */ + + printf("TPM_Process_ReadManuMaintPub: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubKeySerial); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadManuMaintPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Create "checksum" by concatenating data to form (TPM_PERMANENT_DATA -> manuMaintPub + || antiReplay) and passing the concatenated data through SHA-1. */ + if (returnCode == TPM_SUCCESS) { + /* serialize pubkey */ + returnCode = TPM_Pubkey_Store(&pubKeySerial, &(tpm_state->tpm_permanent_data.manuMaintPub)); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubKeySerial, &pubKeyBuffer, &pubKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubKeyLength, pubKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadManuMaintPub: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Export the checksum */ + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubKeySerial); /* @1 */ + return rcf; +} + +#endif diff --git a/src/tpm12/tpm_maint.h b/src/tpm12/tpm_maint.h new file mode 100644 index 0000000..f26f084 --- /dev/null +++ b/src/tpm12/tpm_maint.h @@ -0,0 +1,89 @@ +/********************************************************************************/ +/* */ +/* Maintenance Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_maint.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_MAINT_H +#define TPM_MAINT_H + +#include "tpm_types.h" +#include "tpm_global.h" + + + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_CreateMaintenanceArchive(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 TPM_Process_LoadMaintenanceArchive(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 TPM_Process_KillMaintenanceFeature(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 TPM_Process_LoadManuMaintPub(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 TPM_Process_ReadManuMaintPub(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); + + +#endif diff --git a/src/tpm12/tpm_migration.c b/src/tpm12/tpm_migration.c new file mode 100644 index 0000000..62c59b6 --- /dev/null +++ b/src/tpm12/tpm_migration.c @@ -0,0 +1,4287 @@ +/********************************************************************************/ +/* */ +/* TPM Migration */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_migration.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.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_migration.h" + +/* + TPM_MIGRATIONKEYAUTH +*/ + +/* TPM_Migrationkeyauth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Migrationkeyauth_Init(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + printf(" TPM_Migrationkeyauth_Init:\n"); + TPM_Pubkey_Init(&(tpm_migrationkeyauth->migrationKey)); + tpm_migrationkeyauth->migrationScheme = 0; + TPM_Digest_Init(tpm_migrationkeyauth->digest); + return; +} + +/* TPM_Migrationkeyauth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_Migrationkeyauth_Init() + After use, call TPM_Migrationkeyauth_Delete() to free memory +*/ + +TPM_RESULT TPM_Migrationkeyauth_Load(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Migrationkeyauth_Load:\n"); + /* load migrationKey */ + if (rc == 0) { + rc = TPM_Pubkey_Load(&(tpm_migrationkeyauth->migrationKey), stream, stream_size); + } + /* load migrationScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_migrationkeyauth->migrationScheme), stream, stream_size); + } + /* load digest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_migrationkeyauth->digest, stream, stream_size); + } + return rc; +} + +/* TPM_Migrationkeyauth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Migrationkeyauth_Store(TPM_STORE_BUFFER *sbuffer, + TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Migrationkeyauth_Store:\n"); + /* store migrationKey */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_migrationkeyauth->migrationKey)); + } + /* store migrationScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_migrationkeyauth->migrationScheme); + } + /* store digest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_migrationkeyauth->digest); + } + return rc; +} + +/* TPM_Migrationkeyauth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Migrationkeyauth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Migrationkeyauth_Delete(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + printf(" TPM_Migrationkeyauth_Delete:\n"); + if (tpm_migrationkeyauth != NULL) { + TPM_Pubkey_Delete(&(tpm_migrationkeyauth->migrationKey)); + TPM_Migrationkeyauth_Init(tpm_migrationkeyauth); + } + return; +} + +/* + TPM_MSA_COMPOSITE +*/ + +/* TPM_MsaComposite_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_MsaComposite_Init(TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + printf(" TPM_MsaComposite_Init:\n"); + tpm_msa_composite->MSAlist = 0; + tpm_msa_composite->migAuthDigest = NULL; + return; +} + +/* TPM_MsaComposite_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_MsaComposite_Init() + After use, call TPM_MsaComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_MsaComposite_Load(TPM_MSA_COMPOSITE *tpm_msa_composite, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_MsaComposite_Load:\n"); + /* load MSAlist */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_msa_composite->MSAlist), stream, stream_size); + } + /* MSAlist MUST be one (1) or greater. */ + if (rc == 0) { + if (tpm_msa_composite->MSAlist == 0) { + printf("TPM_MsaComposite_Load: Error, MSAlist is zero\n"); + rc = TPM_INVALID_STRUCTURE; + } + } + /* FIXME add MSAlist limit */ + /* allocate memory for the migAuthDigest array */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_msa_composite->migAuthDigest), + (tpm_msa_composite->MSAlist) * TPM_DIGEST_SIZE); + } + /* load migAuthDigest array */ + for (i = 0 ; (rc == 0) && (i < tpm_msa_composite->MSAlist) ; i++) { + rc = TPM_Digest_Load(tpm_msa_composite->migAuthDigest[i], stream, stream_size); + } + return rc; +} + +/* TPM_MsaComposite_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_MsaComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_MsaComposite_Store:\n"); + /* store MSAlist */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_msa_composite->MSAlist); + } + /* store migAuthDigest array */ + for (i = 0 ; (rc == 0) && (i < tpm_msa_composite->MSAlist) ; i++) { + rc = TPM_Digest_Store(sbuffer, tpm_msa_composite->migAuthDigest[i]); + } + return rc; +} + +/* TPM_MsaComposite_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_MsaComposite_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_MsaComposite_Delete(TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + printf(" TPM_MsaComposite_Delete:\n"); + if (tpm_msa_composite != NULL) { + free(tpm_msa_composite->migAuthDigest); + TPM_MsaComposite_Init(tpm_msa_composite); + } + return; +} + +TPM_RESULT TPM_MsaComposite_CheckMigAuthDigest(TPM_DIGEST tpm_digest, /* value to check vs list */ + TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + TPM_RESULT rc = 0; + uint32_t n; /* count through msaList */ + TPM_BOOL match; + + printf(" TPM_MsaComposite_CheckMigAuthDigest:\n"); + for (n = 0 , match = FALSE ; (n < tpm_msa_composite->MSAlist) && !match ; n++) { + rc = TPM_Digest_Compare(tpm_digest, tpm_msa_composite->migAuthDigest[n]); + if (rc == 0) { + match = TRUE; + } + } + if (match) { + rc = TPM_SUCCESS; + } + else { + printf("TPM_MsaComposite_CheckMigAuthDigest: Error, no match to msaList\n"); + rc = TPM_MA_TICKET_SIGNATURE; + } + return rc; +} + +/* TPM_MsaComposite_CheckSigTicket() + + i. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: + + (1) V1 -> verKeyDigest = msaList -> migAuthDigest[n] + (2) V1 -> signedData = SHA1[restrictTicket] +*/ + +TPM_RESULT TPM_MsaComposite_CheckSigTicket(TPM_DIGEST sigTicket, /* expected HMAC */ + TPM_SECRET tpmProof, /* HMAC key */ + TPM_MSA_COMPOSITE *tpm_msa_composite, + TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + TPM_RESULT rc = 0; + uint32_t n; /* count through msaList */ + TPM_BOOL match; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_MsaComposite_CheckSigTicket: TPM_MSA_COMPOSITE length %u\n", + tpm_msa_composite->MSAlist); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + for (n = 0 , match = FALSE ; + (rc == 0) && (n < tpm_msa_composite->MSAlist) && !match ; n++) { + + if (rc == 0) { + /* verKeyDigest = msaList -> migAuthDigest[n]. The rest of the structure is initialized + by the caller */ + TPM_PrintFour(" TPM_MsaComposite_CheckSigTicket: Checking migAuthDigest: ", + tpm_msa_composite->migAuthDigest[n]); + TPM_Digest_Copy(tpm_cmk_sigticket->verKeyDigest, tpm_msa_composite->migAuthDigest[n]); + /* serialize the TPM_CMK_SIGTICKET structure */ + TPM_Sbuffer_Clear(&sbuffer); /* reset pointers without free */ + rc = TPM_CmkSigticket_Store(&sbuffer, tpm_cmk_sigticket); + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + if (rc == 0) { + rc = TPM_HMAC_Check(&match, + sigTicket, /* expected */ + tpmProof, /* HMAC key*/ + length, buffer, /* TPM_CMK_SIGTICKET */ + 0, NULL); + } + } + if (rc == 0) { + if (!match) { + printf("TPM_MsaComposite_CheckSigTicket: Error, no match to msaList\n"); + rc = TPM_MA_TICKET_SIGNATURE; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_CMK_AUTH +*/ + +/* TPM_CmkAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkAuth_Init(TPM_CMK_AUTH *tpm_cmk_auth) +{ + printf(" TPM_CmkAuth_Init:\n"); + TPM_Digest_Init(tpm_cmk_auth->migrationAuthorityDigest); + TPM_Digest_Init(tpm_cmk_auth->destinationKeyDigest); + TPM_Digest_Init(tpm_cmk_auth->sourceKeyDigest); + return; +} + +/* TPM_CmkAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkAuth_Init() + After use, call TPM_CmkAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkAuth_Load(TPM_CMK_AUTH *tpm_cmk_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkAuth_Load:\n"); + /* load migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->migrationAuthorityDigest, stream, stream_size); + } + /* load destinationKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->destinationKeyDigest, stream, stream_size); + } + /* load sourceKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->sourceKeyDigest, stream, stream_size); + } + return rc; +} + +/* TPM_CmkAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_AUTH *tpm_cmk_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkAuth_Store:\n"); + /* store migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->migrationAuthorityDigest); + } + /* store destinationKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->destinationKeyDigest); + } + /* store sourceKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->sourceKeyDigest); + } + return rc; +} + +/* TPM_CmkAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkAuth_Delete(TPM_CMK_AUTH *tpm_cmk_auth) +{ + printf(" TPM_CmkAuth_Delete:\n"); + if (tpm_cmk_auth != NULL) { + TPM_CmkAuth_Init(tpm_cmk_auth); + } + return; +} + +/* + TPM_CMK_MIGAUTH +*/ + +/* TPM_CmkMigauth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkMigauth_Init(TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + printf(" TPM_CmkMigauth_Init:\n"); + TPM_Digest_Init(tpm_cmk_migauth->msaDigest); + TPM_Digest_Init(tpm_cmk_migauth->pubKeyDigest); + return; +} + +/* TPM_CmkMigauth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkMigauth_Init() + After use, call TPM_CmkMigauth_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkMigauth_Load(TPM_CMK_MIGAUTH *tpm_cmk_migauth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMigauth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_MIGAUTH, stream, stream_size); + } + /* load msaDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_migauth->msaDigest , stream, stream_size); + } + /* load pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_migauth->pubKeyDigest , stream, stream_size); + } + return rc; +} + +/* TPM_CmkMigauth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkMigauth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMigauth_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_MIGAUTH); + } + /* store msaDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_migauth->msaDigest); + } + /* store pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_migauth->pubKeyDigest); + } + return rc; +} + +/* TPM_CmkMigauth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkMigauth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkMigauth_Delete(TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + printf(" TPM_CmkMigauth_Delete:\n"); + if (tpm_cmk_migauth != NULL) { + TPM_CmkMigauth_Init(tpm_cmk_migauth); + } + return; +} + +/* TPM_CmkMigauth_CheckHMAC() checks an HMAC of a TPM_CMK_MIGAUTH object. + + It serializes the structure and HMAC's the result. The common function cannot be used because + 'tpm_hmac' is not part of the structure and cannot be NULL'ed. +*/ + +TPM_RESULT TPM_CmkMigauth_CheckHMAC(TPM_BOOL *valid, /* result */ + TPM_HMAC tpm_hmac, /* expected */ + TPM_SECRET tpm_hmac_key, /* key */ + TPM_CMK_MIGAUTH *tpm_cmk_migauth) /* data */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized TPM_CMK_MIGAUTH */ + + printf(" TPM_CmkMigauth_CheckHMAC:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the TPM_CMK_MIGAUTH structure */ + if (rc == 0) { + rc = TPM_CmkMigauth_Store(&sbuffer, tpm_cmk_migauth); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(valid, /* result */ + tpm_hmac, /* expected */ + tpm_hmac_key, /* key */ + &sbuffer); /* data stream */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_CMK_SIGTICKET +*/ + +/* TPM_CmkSigticket_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkSigticket_Init(TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + printf(" TPM_CmkSigticket_Init:\n"); + TPM_Digest_Init(tpm_cmk_sigticket->verKeyDigest); + TPM_Digest_Init(tpm_cmk_sigticket->signedData); + return; +} + +/* TPM_CmkSigticket_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkSigticket_Init() + After use, call TPM_CmkSigticket_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkSigticket_Load(TPM_CMK_SIGTICKET *tpm_cmk_sigticket, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkSigticket_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_SIGTICKET, stream, stream_size); + } + /* load verKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_sigticket->verKeyDigest , stream, stream_size); + } + /* load signedData */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_sigticket->signedData , stream, stream_size); + } + return rc; +} + +/* TPM_CmkSigticket_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkSigticket_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkSigticket_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_SIGTICKET); + } + /* store verKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_sigticket->verKeyDigest); + } + /* store signedData */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_sigticket->signedData); + } + return rc; +} + +/* TPM_CmkSigticket_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkSigticket_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkSigticket_Delete(TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + printf(" TPM_CmkSigticket_Delete:\n"); + if (tpm_cmk_sigticket != NULL) { + TPM_CmkSigticket_Init(tpm_cmk_sigticket); + } + return; +} + +/* + TPM_CMK_MA_APPROVAL +*/ + +/* TPM_CmkMaApproval_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkMaApproval_Init(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + printf(" TPM_CmkMaApproval_Init:\n"); + TPM_Digest_Init(tpm_cmk_ma_approval->migrationAuthorityDigest); + return; +} + +/* TPM_CmkMaApproval_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkMaApproval_Init() + After use, call TPM_CmkMaApproval_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkMaApproval_Load(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMaApproval_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_MA_APPROVAL, stream, stream_size); + } + /* load migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_ma_approval->migrationAuthorityDigest, stream, stream_size); + } + return rc; +} + +/* TPM_CmkMaApproval_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkMaApproval_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMaApproval_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_MA_APPROVAL); + } + /* store migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_ma_approval->migrationAuthorityDigest); + } + return rc; +} + +/* TPM_CmkMaApproval_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkMaApproval_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkMaApproval_Delete(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + printf(" TPM_CmkMaApproval_Delete:\n"); + if (tpm_cmk_ma_approval != NULL) { + TPM_CmkMaApproval_Init(tpm_cmk_ma_approval); + } + return; +} + +/* TPM_CmkMaApproval_CheckHMAC() generates an HMAC of a TPM_CMK_MIGAUTH object + + It serializes the structure and HMAC's the result.The common function cannot be used because + 'tpm_hmac' is not part of the structure and cannot be NULL'ed. +*/ + +TPM_RESULT TPM_CmkMaApproval_CheckHMAC(TPM_BOOL *valid, /* result */ + TPM_HMAC tpm_hmac, /* expected */ + TPM_SECRET tpm_hmac_key, /* key */ + TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) /* data */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized TPM_CMK_MA_APPROVAL */ + + printf(" TPM_CmkMaApproval_CheckHMAC:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the TPM_CMK_MA_APPROVAL structure */ + if (rc == 0) { + rc = TPM_CmkMaApproval_Store(&sbuffer, tpm_cmk_ma_approval); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(valid, /* result */ + tpm_hmac, /* expected */ + tpm_hmac_key, /* key */ + &sbuffer); /* data stream */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Processing functions +*/ + +/* TPM_CreateBlobCommon() does the steps common to TPM_CreateMigrationBlob and + TPM_CMK_CreateBlob + + It takes a TPM_STORE_ASYMKEY, and + - splits the TPM_STORE_PRIVKEY into k1 (20) and k2 (112) + - builds a TPM_MIGRATE_ASYMKEY using + 'payload_type' + TPM_STORE_ASYMKEY usageAuth, pubDataDigest + k2 as partPrivKey + - serializes the TPM_MIGRATE_ASYMKEY + - OAEP encode using + 'phash' + k1 as seed +*/ + +TPM_RESULT TPM_CreateBlobCommon(TPM_SIZED_BUFFER *outData, /* The modified, encrypted + entity. */ + TPM_STORE_ASYMKEY *d1AsymKey, + TPM_DIGEST pHash, /* for OAEP padding */ + TPM_PAYLOAD_TYPE payload_type, + TPM_SIZED_BUFFER *random, /* String used for xor encryption */ + TPM_PUBKEY *migrationKey) /* public key of the migration + facility */ +{ + TPM_RESULT rc = 0; + uint32_t o1_size; + BYTE *o1; + BYTE *r1; + BYTE *x1; + + printf("TPM_CreateBlobCommon:\n"); + o1 = NULL; /* freed @1 */ + r1 = NULL; /* freed @2 */ + x1 = NULL; /* freed @3 */ + if (rc == 0) { + TPM_StoreAsymkey_GetO1Size(&o1_size, d1AsymKey); + } + if (rc == 0) { + rc = TPM_Malloc(&o1, o1_size); + } + if (rc == 0) { + rc = TPM_Malloc(&r1, o1_size); + } + if (rc == 0) { + rc = TPM_Malloc(&x1, o1_size); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_StoreO1(o1, + o1_size, + d1AsymKey, + pHash, + payload_type, + d1AsymKey->usageAuth); + } + /* NOTE Comments from TPM_CreateMigrationBlob rev 81 */ + /* d. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of o1. Return + r1 in the Random parameter. */ + if (rc == 0) { + rc = TPM_Random(r1, o1_size); + } + /* e. Create x1 by XOR of o1 with r1 */ + if (rc == 0) { + TPM_PrintFourLimit("TPM_CreateBlobCommon: r1 -", r1, o1_size); + TPM_XOR(x1, o1, r1, o1_size); + TPM_PrintFourLimit("TPM_CreateBlobCommon: x1 -", x1, o1_size); + /* f. Copy r1 into the output field "random".*/ + rc = TPM_SizedBuffer_Set(random, o1_size, r1); + } + /* g. Encrypt x1 with the migration public key included in migrationKeyAuth. */ + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Pubkey(outData, + x1, + o1_size, + migrationKey); + TPM_PrintFour("TPM_CreateBlobCommon: outData", outData->buffer); + } + free(o1); /* @1 */ + free(r1); /* @2 */ + free(x1); /* @3 */ + return rc; +} + +/* 11.1 TPM_CreateMigrationBlob rev 109 + + The TPM_CreateMigrationBlob command implements the first step in the process of moving a + migratable key to a new parent or platform. Execution of this command requires knowledge of the + migrationAuth field of the key to be migrated. + + Migrate mode is generally used to migrate keys from one TPM to another for backup, upgrade or to + clone a key on another platform. To do this, the TPM needs to create a data blob that another TPM + can deal with. This is done by loading in a backup public key that will be used by the TPM to + create a new data blob for a migratable key. + + The TPM Owner does the selection and authorization of migration public keys at any time prior to + the execution of TPM_CreateMigrationBlob by performing the TPM_AuthorizeMigrationKey command. + + IReWrap mode is used to directly move the key to a new parent (either on this platform or + another). The TPM simply re-encrypts the key using a new parent, and outputs a normal encrypted + element that can be subsequently used by a TPM_LoadKey command. + + TPM_CreateMigrationBlob implicitly cannot be used to migrate a non-migratory key. No explicit + check is required. Only the TPM knows tpmProof. Therefore it is impossible for the caller to + submit an authorization value equal to tpmProof and migrate a non-migratory key. +*/ + +TPM_RESULT TPM_Process_CreateMigrationBlob(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 that can decrypt encData. */ + TPM_MIGRATE_SCHEME migrationType; /* The migration type, either MIGRATE or REWRAP */ + TPM_MIGRATIONKEYAUTH migrationKeyAuth; /* Migration public key and its authorization + digest. */ + 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; /* Continue use flag for parent session */ + TPM_AUTHDATA parentAuth; /* Authorization HMAC key: parentKey.usageAuth. */ + TPM_AUTHHANDLE entityAuthHandle; /* The authorization handle used for the encrypted + entity. */ + TPM_NONCE entitynonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueEntitySession = TRUE; /* Continue use flag for entity session */ + TPM_AUTHDATA entityAuth; /* Authorization HMAC key: entity.migrationAuth. */ + + /* 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_SECRET *hmacKey; + TPM_SECRET *entityHmacKey; + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; /* decryption of encData */ + uint32_t d1DecryptLength = 0; /* actual valid data */ + unsigned char *stream; /* for deserializing decrypted encData */ + uint32_t stream_size; + TPM_STORE_ASYMKEY d1AsymKey; /* structure from decrypted encData */ + TPM_STORE_BUFFER mka_sbuffer; /* serialized migrationKeyAuth */ + const unsigned char *mka_buffer; + uint32_t mka_length; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* String used for xor encryption */ + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + + printf("TPM_Process_CreateMigrationBlob: Ordinal Entry\n"); + TPM_Migrationkeyauth_Init(&migrationKeyAuth); /* freed @1 */ + TPM_SizedBuffer_Init(&encData); /* freed @2 */ + TPM_SizedBuffer_Init(&random); /* freed @3 */ + TPM_SizedBuffer_Init(&outData); /* freed @4 */ + d1Decrypt = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&d1AsymKey); /* freed @6 */ + TPM_Sbuffer_Init(&mka_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationType */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: parentHandle %08x\n", parentHandle); + returnCode = TPM_Load16(&migrationType, &command, ¶mSize); + } + /* get migrationKeyAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &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_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&parentAuthHandle, + &parentAuthHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CreateMigrationBlob: parentAuthHandle %08x\n", parentAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&entityAuthHandle, + &entityAuthHandleValid, + entitynonceOdd, + &continueEntitySession, + entityAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: entityAuthHandle %08x\n", entityAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateMigrationBlob: 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 + */ + /* The TPM does not check the PCR values when migrating values locked to a PCR. */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* read-only, do not check PCR's */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&parent_auth_session_data, + &hmacKey, + tpm_state, + parentAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate that parentAuth authorizes the use of the key pointed to by parentHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + parent_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* if there is no parent authorization, check that the parent authDataUsage is TPM_AUTH_NEVER */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CreateMigrationBlob: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. 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_CreateMigrationBlob: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 a TPM_STORE_ASYMKEY structure by decrypting encData using the key pointed to by + parentHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Decrypting encData\n"); + /* decrypt with the parent key to a stream */ + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + /* deserialize the stream to a TPM_STORE_ASYMKEY d1AsymKey */ + if (returnCode == TPM_SUCCESS) { + stream = d1Decrypt; + stream_size = d1DecryptLength; + returnCode = TPM_StoreAsymkey_Load(&d1AsymKey, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* a. Verify that d1 -> payload is TPM_PT_ASYM. */ + if (returnCode == TPM_SUCCESS) { + if (d1AsymKey.payload != TPM_PT_ASYM) { + printf("TPM_Process_CreateMigrationBlob: Error, bad payload %02x\n", + d1AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + } + /* 4. Validate that entityAuth authorizes the migration of d1. The validation MUST use d1 -> + migrationAuth as the secret. */ + /* get the second session data */ + /* The second authorisation session (using entityAuth) MUST be OIAP because OSAP does not have a + suitable entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&entity_auth_session_data, + &entityHmacKey, + tpm_state, + entityAuthHandle, + TPM_PID_OIAP, + TPM_ET_KEYHANDLE, + ordinal, + NULL, + &(d1AsymKey.migrationAuth), + NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *entityHmacKey, /* HMAC key */ + inParamDigest, + entity_auth_session_data, /* authorization session */ + entitynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueEntitySession, + entityAuth); /* Authorization digest for input */ + } + /* 5. Validate that migrationKeyAuth -> digest is the SHA-1 hash of (migrationKeyAuth -> + migrationKey || migrationKeyAuth -> migrationScheme || TPM_PERMANENT_DATA -> tpmProof). */ + /* first serialize the TPM_PUBKEY migrationKeyAuth -> migrationKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Verifying migrationKeyAuth\n"); + returnCode = TPM_Pubkey_Store(&mka_sbuffer, &(migrationKeyAuth.migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialization result */ + TPM_Sbuffer_Get(&mka_sbuffer, &mka_buffer, &mka_length); + /* compare to migrationKeyAuth -> digest */ + returnCode = TPM_SHA1_Check(migrationKeyAuth.digest, + mka_length, mka_buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationKeyAuth.migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* 6. If migrationType == TPM_MS_MIGRATE the TPM SHALL perform the following actions: */ + if ((returnCode == TPM_SUCCESS) && (migrationType == TPM_MS_MIGRATE)) { + printf("TPM_Process_CreateMigrationBlob: migrationType TPM_MS_MIGRATE\n"); + /* a. Build two byte arrays, K1 and K2: */ + /* i. K1 = d1.privKey[0..19] (d1.privKey.keyLength + 16 bytes of d1.privKey.key), sizeof(K1) + = 20 */ + /* ii. K2 = d1.privKey[20..131] (position 16-127 of TPM_STORE_ASYMKEY. privKey.key) + (position 16-127 of d1 . privKey.key), sizeof(K2) = 112 */ + /* b. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* i. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_MIGRATE */ + /* ii. TPM_MIGRATE_ASYMKEY.usageAuth = d1.usageAuth */ + /* iii. TPM_MIGRATE_ASYMKEY.pubDataDigest = d1.pubDataDigest */ + /* iv. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* v. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + /* c. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* i. m = M1 the TPM_MIGRATE_ASYMKEY structure */ + /* ii. pHash = d1->migrationAuth */ + /* iii. seed = s1 = K1 */ + /* d. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of + o1. Return r1 in the Random parameter. */ + /* e. Create x1 by XOR of o1 with r1*/ + /* f. Copy r1 into the output field "random".*/ + /* g. Encrypt x1 with the migration public key included in migrationKeyAuth.*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateBlobCommon(&outData, /* output */ + &d1AsymKey, /* TPM_STORE_ASYMKEY */ + d1AsymKey.migrationAuth, /* pHash */ + TPM_PT_MIGRATE, /* payload type */ + &random, /* string for XOR encryption */ + &(migrationKeyAuth.migrationKey)); /* TPM_PUBKEY */ + } + } + /* 7. If migrationType == TPM_MS_REWRAP the TPM SHALL perform the following actions: */ + else if ((returnCode == TPM_SUCCESS) && (migrationType == TPM_MS_REWRAP)) { + printf("TPM_Process_CreateMigrationBlob: migrationType TPM_MS_REWRAP\n"); + /* a. Rewrap the key using the public key in migrationKeyAuth, keeping the existing contents + of that key. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncrypt_Pubkey(&outData, + d1Decrypt, /* decrypted encData parameter */ + d1DecryptLength, + &(migrationKeyAuth.migrationKey)); + } + /* b. Set randomSize to 0 in the output parameter array */ + /* NOTE Done by TPM_SizedBuffer_Init() */ + } + /* 8. Else */ + /* a. Return TPM_BAD_PARAMETER */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Error, illegal migrationType %04hx\n", + migrationType); + returnCode = TPM_BAD_PARAMETER; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateMigrationBlob: 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 random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return outData */ + 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) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + parent_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *entityHmacKey, /* HMAC key */ + 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); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) + && parentAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + parentAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueEntitySession) && + entityAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + entityAuthHandle); + } + /* + cleanup + */ + TPM_Migrationkeyauth_Delete(&migrationKeyAuth); /* @1 */ + TPM_SizedBuffer_Delete(&encData); /* @2 */ + TPM_SizedBuffer_Delete(&random); /* @3 */ + TPM_SizedBuffer_Delete(&outData); /* @4 */ + free(d1Decrypt); /* @5 */ + TPM_StoreAsymkey_Delete(&d1AsymKey); /* @6 */ + TPM_Sbuffer_Delete(&mka_sbuffer); /* @7 */ + return rcf; +} + + + +/* 11.2 TPM_ConvertMigrationBlob rev 87 + + This command takes a migration blob and creates a normal wrapped blob. The migrated blob must be + loaded into the TPM using the normal TPM_LoadKey function. + + Note that the command migrates private keys, only. The migration of the associated public keys is + not specified by TPM because they are not security sensitive. Migration of the associated public + keys may be specified in a platform specific specification. A TPM_KEY structure must be recreated + before the migrated key can be used by the target TPM in a LoadKey command. +*/ + +/* The relationship between Create and Convert parameters are: + + Create: k1 || k2 = privKey + m = TPM_MIGRATE_ASYMKEY, partPrivKey = k2 + o1 = OAEP (m), seed = k1 + x1 = o1 ^ r1 + out = pub (x1) + Convert: + d1 = priv (in) + o1 = d1 ^ r1 + m1, seed = OAEP (o1) + k1 = seed || partPrivKey +*/ + +TPM_RESULT TPM_Process_ConvertMigrationBlob(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 a loaded key that can decrypt keys. */ + TPM_SIZED_BUFFER inData; /* The XOR'd and encrypted key */ + TPM_SIZED_BUFFER random; /* Random value used to hide key data. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest that authorizes the inputs and + the migration of the key in 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_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; + uint32_t d1DecryptLength = 0; /* actual valid data */ + BYTE *o1Oaep; + TPM_STORE_ASYMKEY d2AsymKey; + TPM_STORE_BUFFER d2_sbuffer; + + /* 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 encrypted private key that can be loaded with + TPM_LoadKey */ + + printf("TPM_Process_ConvertMigrationBlob: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_SizedBuffer_Init(&random); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + d1Decrypt = NULL; /* freed @4 */ + o1Oaep = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&d2AsymKey); /* freed @6 */ + TPM_Sbuffer_Init(&d2_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: parentHandle %08x\n", parentHandle); + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* get random */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&random, &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, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ConvertMigrationBlob: 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 + */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ConvertMigrationBlob: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* 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, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key in parentHandle */ + 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, + parentAuth); /* Authorization digest for input */ + } + /* 2. If the keyUsage field of the key referenced by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_ConvertMigrationBlob: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 by decrypting the inData area using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: Decrypting inData\n"); + TPM_PrintFourLimit("TPM_Process_ConvertMigrationBlob: inData", inData.buffer, inData.size); + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + inData.buffer, /* encrypted data */ + inData.size, + parentKey); + } + /* the random input parameter must be the same length as the decrypted data */ + if (returnCode == TPM_SUCCESS) { + if (d1DecryptLength != random.size) { + printf("TPM_Process_ConvertMigrationBlob: Error " + "decrypt data length %u random size %u\n", + d1DecryptLength, random.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* allocate memory for o1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: d1 length %u\n", d1DecryptLength); + TPM_PrintFourLimit("TPM_Process_ConvertMigrationBlob: d1 -", d1Decrypt, d1DecryptLength); + /* 4. Create o1 by XOR d1 and random parameter */ + TPM_XOR(o1Oaep, d1Decrypt, random.buffer, d1DecryptLength); + /* 5. Create m1 a TPM_MIGRATE_ASYMKEY structure, seed and pHash by OAEP decoding o1 */ + /* NOTE TPM_StoreAsymkey_LoadO1() extracts TPM_STORE_ASYMKEY from the OAEP encoded + TPM_MIGRATE_ASYMKEY. */ + returnCode = TPM_StoreAsymkey_LoadO1(&d2AsymKey, o1Oaep, d1DecryptLength); + } + /* 6. Create k1 by combining seed and the TPM_MIGRATE_ASYMKEY -> partPrivKey field */ + /* NOTE Done by TPM_StoreAsymkey_LoadO1 () */ + /* 7. Create d2 a TPM_STORE_ASYMKEY structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Verify that m1 -> payload == TPM_PT_MIGRATE */ + /* NOTE TPM_StoreAsymkey_LoadO1() copied TPM_MIGRATE_ASYMKEY -> payload to TPM_STORE_ASYMKEY + -> payload */ + if (d2AsymKey.payload != TPM_PT_MIGRATE) { + printf("TPM_Process_ConvertMigrationBlob: Error, invalid payload %02x\n", + d2AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + } + if (returnCode == TPM_SUCCESS) { + /* b. Set d2 -> payload = TPM_PT_ASYM */ + d2AsymKey.payload = TPM_PT_ASYM; + /* c. Set d2 -> usageAuth to m1 -> usageAuth */ + /* d. Set d2 -> migrationAuth to pHash */ + /* e. Set d2 -> pubDataDigest to m1 -> pubDataDigest */ + /* f. Set d2 -> privKey field to k1 */ + /* NOTE Done by TPM_StoreAsymkey_LoadO1() */ + /* 9. Create outData using the key in parentHandle to perform the encryption */ + /* serialize d2key to d2 */ + returnCode = TPM_StoreAsymkey_Store(&d2_sbuffer, FALSE, &d2AsymKey); + } + /* encrypt d2 with parentKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncryptSbuffer_Key(&outData, &d2_sbuffer, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ConvertMigrationBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + 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) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + TPM_SizedBuffer_Delete(&random); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + free(d1Decrypt); /* @4 */ + free(o1Oaep); /* @5 */ + TPM_StoreAsymkey_Delete(&d2AsymKey); /* @6 */ + TPM_Sbuffer_Delete(&d2_sbuffer); /* @7 */ + return rcf; +} + +/* 11.3 TPM_AuthorizeMigrationKey rev 114 + + This command creates an authorization blob, to allow the TPM owner to specify which migration + facility they will use and allow users to migrate information without further involvement with + the TPM owner. + + It is the responsibility of the TPM Owner to determine whether migrationKey is appropriate for + migration. The TPM checks just the cryptographic strength of migrationKey. +*/ + +TPM_RESULT TPM_Process_AuthorizeMigrationKey(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_MIGRATE_SCHEME migrationScheme; /* Type of migration operation that is to be permitted for + this key. */ + TPM_PUBKEY migrationKey; /* The public key to be authorized. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_RSA_KEY_PARMS *rsa_key_parms; /* for migrationKey */ + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + uint32_t length; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_MIGRATIONKEYAUTH outData; /* (f1) Returned public key and authorization digest. */ + + printf("TPM_Process_AuthorizeMigrationKey: Ordinal Entry\n"); + TPM_Pubkey_Init(&migrationKey); /* freed @1 */ + TPM_Migrationkeyauth_Init(&outData); /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationScheme */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&migrationScheme, &command, ¶mSize); + } + /* get migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&migrationKey, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_AuthorizeMigrationKey: 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. Check that the cryptographic strength of migrationKey is at least that of a 2048 bit RSA + key. If migrationKey is an RSA key, this means that migrationKey MUST be 2048 bits or greater + and MUST use the default exponent. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(migrationKey.algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + if (rsa_key_parms->keyLength < 2048) { + printf("TPM_Process_AuthorizeMigrationKey: Error, " + "migrationKey length %u less than 2048\n", + rsa_key_parms->keyLength); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParams_CheckDefaultExponent(&(rsa_key_parms->exponent)); + } + /* 2. Validate the AuthData to use the TPM by the TPM Owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. Create a f1 a TPM_MIGRATIONKEYAUTH structure */ + /* NOTE: This is outData */ + /* 4. Verify that migrationKey-> algorithmParms -> encScheme is TPM_ES_RSAESOAEP_SHA1_MGF1, and + return the error code TPM_INAPPROPRIATE_ENC if it is not */ + if (returnCode == TPM_SUCCESS) { + if (migrationKey.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_AuthorizeMigrationKey: Error, " + "migrationKey encScheme %04hx must be TPM_ES_RSAESOAEP_SHA1_MGF1\n", + migrationKey.algorithmParms.encScheme); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* 5. Set f1 -> migrationKey to the input migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Copy(&(outData.migrationKey), &(migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Set f1 -> migrationScheme to the input migrationScheme */ + outData.migrationScheme = migrationScheme; + /* 7. Create v1 by concatenating (migrationKey || migrationScheme || TPM_PERMANENT_DATA -> + tpmProof) */ + /* 8. Create h1 by performing a SHA-1 hash of v1 */ + /* first serialize the TPM_PUBKEY migrationKey */ + returnCode = TPM_Pubkey_Store(&sbuffer, &migrationKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + /* 9. Set f1 -> digest to h1 */ + returnCode = TPM_SHA1(outData.digest, + length, buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_AuthorizeMigrationKey: 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; + /* 10. Return f1 as outData */ + returnCode = TPM_Migrationkeyauth_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, + *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_Pubkey_Delete(&migrationKey); /* @1 */ + TPM_Migrationkeyauth_Delete(&outData); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rcf; +} + +/* 11.4 TPM_MigrateKey rev 87 + + The TPM_MigrateKey command performs the function of a migration authority. + + The command is relatively simple; it just decrypts the input packet (coming from + TPM_CreateMigrationBlob or TPM_CMK_CreateBlob) and then re-encrypts it with the input public + key. The output of this command would then be sent to TPM_ConvertMigrationBlob or + TPM_CMK_ConvertMigration on the target TPM. + + TPM_MigrateKey does not make ANY assumptions about the contents of the encrypted blob. Since it + does not have the XOR string, it cannot actually determine much about the key that is being + migrated. + + This command exists to permit the TPM to be a migration authority. If used in this way, it is + expected that the physical security of the system containing the TPM and the AuthData value for + the MA key would be tightly controlled. + + To prevent the execution of this command using any other key as a parent key, this command works + only if keyUsage for maKeyHandle is TPM_KEY_MIGRATE. +*/ + +TPM_RESULT TPM_Process_MigrateKey(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 maKeyHandle; /* Handle of the key to be used to migrate the key. */ + TPM_PUBKEY pubKey; /* Public key to which the blob is to be migrated */ + TPM_SIZED_BUFFER inData; /* The input blob */ + + TPM_AUTHHANDLE maAuthHandle; /* The authorization session handle used for maKeyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key to be + signed. HMAC key: maKeyHandle.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 maAuthHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *maKey = NULL; /* the key specified by maKeyHandle */ + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* for maKey */ + TPM_SECRET *maKeyUsageAuth; + TPM_BOOL maPCRStatus; + uint32_t decrypt_data_size; /* resulting decrypted data size */ + BYTE *decrypt_data = NULL; /* The resulting decrypted 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 re-encrypted blob */ + + printf("TPM_Process_MigrateKey: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + TPM_Pubkey_Init(&pubKey); /* freed @4 */ + /* + get inputs + */ + /* get maKeyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&maKeyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pubKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: maKeyHandle %08x\n", maKeyHandle); + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &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(&maAuthHandle, + &maAuthHandleValid, + nonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_MigrateKey: 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) { + maAuthHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that keyAuth authorizes the use of the key pointed to by maKeyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&maKey, &maPCRStatus, tpm_state, maKeyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get maKeyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&maKeyUsageAuth, maKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_MigrateKey: maAuthHandle %08x\n", maAuthHandle); + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + maAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + maKey, + maKeyUsageAuth, /* OIAP */ + maKey->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, + keyAuth); /* Authorization digest for input */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (maKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_MigrateKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. The TPM validates that the key pointed to by maKeyHandle has a key usage value of + TPM_KEY_MIGRATE, and that the allowed encryption scheme is TPM_ES_RSAESOAEP_SHA1_MGF1. */ + if (returnCode == TPM_SUCCESS) { + if (maKey->keyUsage != TPM_KEY_MIGRATE) { + printf("TPM_Process_MigrateKey: Error, keyUsage %04hx not TPM_KEY_MIGRATE\n", + maKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + else if (maKey->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_MigrateKey: Error, encScheme %04hx not TPM_ES_RSAESOAEP_SHA_MGF1\n", + maKey->algorithmParms.encScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 3. The TPM validates that pubKey is of a size supported by the TPM and that its size is + consistent with the input blob and maKeyHandle. */ + /* NOTE: Let the encryption step do this step */ + /* 4. The TPM decrypts inData and re-encrypts it using pubKey. */ + /* get the TPM_RSA_KEY_PARMS associated with maKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, &(maKey->algorithmParms)); + } + /* decrypt using maKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: Decrypt using maKey\n"); + returnCode = + TPM_RSAPrivateDecryptMalloc(&decrypt_data, /* decrypted data, freed @3 */ + &decrypt_data_size, /* actual size of decrypt data */ + inData.buffer, + inData.size, + maKey); + + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: Encrypt using pubKey\n"); + returnCode = TPM_RSAPublicEncrypt_Pubkey(&outData, /* encrypted data */ + decrypt_data, + decrypt_data_size, + &pubKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_MigrateKey: 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); + /* 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, /* 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) && + maAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, maAuthHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + free(decrypt_data); /* @3 */ + TPM_Pubkey_Delete(&pubKey); /* @4 */ + return rcf; +} + +/* 11.7 TPM_CMK_CreateKey rev 114 + + The TPM_CMK_CreateKey command both generates and creates a secure storage bundle for asymmetric + keys whose migration is controlled by a migration authority. + + TPM_CMK_CreateKey is very similar to TPM_CreateWrapKey, but: (1) the resultant key must be a + migratable key and can be migrated only by TPM_CMK_CreateBlob; (2) the command is Owner + authorized via a ticket. + + TPM_CMK_CreateKey creates an otherwise normal migratable key except that (1) migrationAuth is an + HMAC of the migration authority and the new key's public key, signed by tpmProof (instead of + being tpmProof); (2) the migrationAuthority bit is set TRUE; (3) the payload type is + TPM_PT_MIGRATE_RESTRICTED. + + The migration-selection/migration authority is specified by passing in a public key (actually the + digests of one or more public keys, so more than one migration authority can be specified). +*/ + +TPM_RESULT TPM_Process_CMK_CreateKey(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 a loaded key that can perform key wrapping. */ + TPM_ENCAUTH dataUsageAuth; /* Encrypted usage authorization data for the key. */ + TPM_KEY keyInfo; /* Information about key to be created, pubkey.keyLength and + keyInfo.encData elements are 0. MUST be TPM_KEY12 */ + TPM_HMAC migrationAuthorityApproval;/* A ticket, created by the TPM Owner using + TPM_CMK_ApproveMA, approving a TPM_MSA_COMPOSITE + structure */ + TPM_DIGEST migrationAuthorityDigest;/* The digest of a TPM_MSA_COMPOSITE structure */ + + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parent key + authorization. Must be an OSAP session. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization session digest that authorizes the use + of the public key in 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 entityAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_BOOL hmacValid; /* for migrationAuthorityApproval */ + TPM_SECRET du1DecryptAuth; + TPM_STORE_ASYMKEY *wrappedStoreAsymkey; /* substructure of wrappedKey */ + TPM_CMK_MA_APPROVAL m1CmkMaApproval; + TPM_CMK_MIGAUTH m2CmkMigauth; + int ver; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY wrappedKey; /* The TPM_KEY structure which includes the public and + encrypted private key. MUST be TPM_KEY12 */ + + printf("TPM_Process_CMK_CreateKey: Ordinal Entry\n"); + TPM_Key_Init(&keyInfo); /* freed @1 */ + TPM_Key_Init(&wrappedKey); /* freed @2 */ + TPM_CmkMaApproval_Init(&m1CmkMaApproval); /* freed @3 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @4 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dataUsageAuth */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Authdata_Load(dataUsageAuth, &command, ¶mSize); + } + /* get keyInfo */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&keyInfo, &command, ¶mSize); + } + /* get migrationAuthorityApproval */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityApproval, &command, ¶mSize); + } + /* get migrationAuthorityDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityDigest, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the authorization to use the key pointed to by parentHandle. Return TPM_AUTHFAIL + on any error. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the session data */ + /* 2. Validate the session type for parentHandle is OSAP. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 3. If the TPM is not designed to create a key of the type requested in keyInfo, return the + error code TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckProperties(&ver, &keyInfo, 0, + tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_Process_CMK_CreateKey: key parameters v = %d\n", ver); + } + /* 4. Verify that parentHandle->keyUsage equals TPM_KEY_STORAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking parent key\n"); + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CMK_CreateKey: Error, parent keyUsage not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Verify that parentHandle-> keyFlags-> migratable == FALSE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_CreateKey: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. If keyInfo -> keyFlags -> migratable is FALSE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking key flags\n"); + if (!(keyInfo.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo migratable is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If keyInfo -> keyFlags -> migrateAuthority is FALSE , return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (!(keyInfo.keyFlags & TPM_MIGRATEAUTHORITY)) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo migrateauthority is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 8. Verify that the migration authority is authorized */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking migration authority authorization\n"); + /* a. Create M1 a TPM_CMK_MA_APPROVAL structure */ + /* NOTE Done by TPM_CmkMaApproval_Init() */ + /* i. Set M1 ->migrationAuthorityDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m1CmkMaApproval.migrationAuthorityDigest, migrationAuthorityDigest); + /* b. Verify that migrationAuthorityApproval == HMAC(M1) using tpmProof as the secret and + return error TPM_MA_AUTHORITY on mismatch */ + returnCode = + TPM_CmkMaApproval_CheckHMAC(&hmacValid, + migrationAuthorityApproval, /* expect */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m1CmkMaApproval); + if (!hmacValid) { + printf("TPM_Process_CMK_CreateKey: Error, Invalid migrationAuthorityApproval\n"); + returnCode = TPM_MA_AUTHORITY; + } + } + /* 9. Validate key parameters */ + /* a. keyInfo -> keyUsage MUST NOT be TPM_KEY_IDENTITY or TPM_KEY_AUTHCHANGE. If it is, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking key usage\n"); + if ((keyInfo.keyUsage == TPM_KEY_IDENTITY) || + (keyInfo.keyUsage == TPM_KEY_AUTHCHANGE)) { + printf("TPM_Process_CMK_CreateKey: Error, invalid keyInfo -> keyUsage %04hx\n", + keyInfo.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 10. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then */ + /* a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS */ + /* b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + /* c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* 11. If keyInfo -> keyUsage equals TPM_KEY_STORAGE or TPM_KEY_MIGRATE */ + /* a. algorithmID MUST be TPM_ALG_RSA */ + /* b. encScheme MUST be TPM_ES_RSAESOAEP_SHA1_MGF1 */ + /* c. sigScheme MUST be TPM_SS_NONE */ + /* d. key size MUST be 2048 */ + /* e. exponentSize MUST be 0 */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* 12. If keyInfo -> tag is NOT TPM_TAG_KEY12 return TPM_INVALID_STRUCTURE */ + if (returnCode == TPM_SUCCESS) { + if (ver != 2) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo must be TPM_TAG_KEY12\n"); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* 13. Map wrappedKey to a TPM_KEY12 structure */ + /* NOTE: Not required. TPM_KEY functions handle TPM_KEY12 subclass */ + /* 14. Create DU1 by decrypting dataUsageAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(du1DecryptAuth, + NULL, + dataUsageAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + /* 15. Set continueAuthSession to FALSE */ + continueAuthSession = FALSE; + /* 16. Generate asymmetric key according to algorithm information in keyInfo */ + /* 17. Fill in the wrappedKey structure with information from the newly generated key. */ + printf("TPM_Process_CMK_CreateKey: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&wrappedKey, + tpm_state, + parentKey, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, /* TPM_KEY12 */ + keyInfo.keyUsage, + keyInfo.keyFlags, + keyInfo.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(keyInfo.algorithmParms), /* TPM_KEY_PARMS */ + keyInfo.tpm_pcr_info, /* TPM_PCR_INFO */ + keyInfo.tpm_pcr_info_long); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&wrappedStoreAsymkey, + &wrappedKey); + } + if (returnCode == TPM_SUCCESS) { + /* a. Set wrappedKey -> encData -> usageAuth to DU1 */ + TPM_Secret_Copy(wrappedStoreAsymkey->usageAuth, du1DecryptAuth); + /* b. Set wrappedKey -> encData -> payload to TPM_PT_MIGRATE_RESTRICTED */ + wrappedStoreAsymkey->payload = TPM_PT_MIGRATE_RESTRICTED; + /* c. Create thisPubKey, a TPM_PUBKEY structure containing wrappedKey's public key. */ + /* NOTE All that is really needed is its digest, which is calculated directly */ + } + if (returnCode == TPM_SUCCESS) { + /* d. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* i. Set M2 -> msaDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationAuthorityDigest); + /* ii. Set M2 -> pubKeyDigest to SHA-1 (thisPubKey) */ + returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, &wrappedKey); + /* e. Set wrappedKey -> encData -> migrationAuth equal to HMAC(M2), using tpmProof as the + shared secret */ + returnCode = TPM_HMAC_GenerateStructure + (wrappedStoreAsymkey->migrationAuth, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMigauth_Store); /* store function */ + } + /* 18. If keyInfo->PCRInfoSize is non-zero */ + /* a. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO_LONG structure */ + /* b. Set wrappedKey -> pcrInfo to keyInfo -> pcrInfo */ + /* b. Set wrappedKey -> digestAtCreation to the TPM_COMPOSITE_HASH indicated by + creationPCRSelection */ + /* c. Set wrappedKey -> localityAtCreation to TPM_STANY_FLAGS -> localityModifier */ + /* NOTE This is done during TPM_Key_GenerateRSA() */ + /* 19. Encrypt the private portions of the wrappedKey structure using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GenerateEncData(&wrappedKey, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateKey: 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; + /* 20. Return the newly generated key in the wrappedKey parameter */ + returnCode = TPM_Key_Store(response, &wrappedKey); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Key_Delete(&keyInfo); /* @1 */ + TPM_Key_Delete(&wrappedKey); /* @2 */ + TPM_CmkMaApproval_Delete(&m1CmkMaApproval); /* @3 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @4 */ + return rcf; +} + + +/* 11.5 TPM_CMK_CreateTicket rev 101 + + The TPM_verifySignature command uses a public key to verify the signature over a digest. + + TPM_verifySignature returns a ticket that can be used to prove to the same TPM that signature + verification with a particular public key was successful. +*/ + +TPM_RESULT TPM_Process_CMK_CreateTicket(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_PUBKEY verificationKey; /* The public key to be used to check signatureValue */ + TPM_DIGEST signedData; /* The data to be verified */ + TPM_SIZED_BUFFER signatureValue; /* The signatureValue to be verified */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and owner. HMAC key: + ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_CMK_SIGTICKET m2CmkSigticket; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_HMAC sigTicket; /* Ticket that proves digest created on this TPM */ + + printf("TPM_Process_CMK_CreateTicket: Ordinal Entry\n"); + TPM_Pubkey_Init(&verificationKey); /* freed @1 */ + TPM_SizedBuffer_Init(&signatureValue); /* freed @2 */ + TPM_CmkSigticket_Init(&m2CmkSigticket); /* freed @3 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get verificationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&verificationKey, &command, ¶mSize); + } + /* get signedData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(signedData, &command, ¶mSize); + } + /* get signatureValue */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&signatureValue, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateTicket: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner authorization to use the command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. Validate that the key type and algorithm are correct */ + /* a. Validate that verificationKey -> algorithmParms -> algorithmID == TPM_ALG_RSA */ + if (returnCode == TPM_SUCCESS) { + if (verificationKey.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect algorithmID %08x\n", + verificationKey.algorithmParms.algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* b. Validate that verificationKey -> algorithmParms ->encScheme == TPM_ES_NONE */ + if (returnCode == TPM_SUCCESS) { + if (verificationKey.algorithmParms.encScheme != TPM_ES_NONE) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect encScheme %04hx\n", + verificationKey.algorithmParms.encScheme); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* c. Validate that verificationKey ->algorithmParms ->sigScheme is + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((verificationKey.algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (verificationKey.algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect sigScheme %04hx\n", + verificationKey.algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Use verificationKey to verify that signatureValue is a valid signature on signedData, and + return error TPM_BAD_SIGNATURE on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateTicket: Verifying signature\n"); + returnCode = TPM_RSAVerifyH(&signatureValue, /* signature */ + signedData, /* data that was signed */ + TPM_DIGEST_SIZE, /* size of signed data */ + &verificationKey); /* TPM_PUBKEY public key */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateTicket: Error verifying signature\n"); + } + } + /* 4. Create M2 a TPM_CMK_SIGTICKET */ + /* NOTE Done by TPM_CmkSigticket_Init() */ + /* a. Set M2 -> verKeyDigest to the SHA-1 (verificationKey) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkSigticket.verKeyDigest, &verificationKey, + (TPM_STORE_FUNCTION_T)TPM_Pubkey_Store); + } + if (returnCode == TPM_SUCCESS) { + /* b. Set M2 -> signedData to signedData */ + TPM_Digest_Copy(m2CmkSigticket.signedData, signedData); + /* 5. Set sigTicket = HMAC(M2) signed by using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (sigTicket, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkSigticket, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkSigticket_Store); /* store function */ + } + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateTicket: 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 sigTicket */ + returnCode = TPM_Digest_Store(response, sigTicket); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&verificationKey); /* @1 */ + TPM_SizedBuffer_Delete(&signatureValue); /* @2 */ + TPM_CmkSigticket_Delete(&m2CmkSigticket); /* @3 */ + return rcf; +} + + +/* 11.9 TPM_CMK_CreateBlob rev 114 + + TPM_CMK_CreateBlob command is very similar to TPM_CreateMigrationBlob, except that it: (1) uses + an extra ticket (restrictedKeyAuth) instead of a migrationAuth authorization session; (2) uses + the migration options TPM_MS_RESTRICT_MIGRATE or TPM_MS_RESTRICT_APPROVE; (3) produces a wrapped + key blob whose migrationAuth is independent of tpmProof. + + If the destination (parent) public key is the MA, migration is implicitly permitted. Further + checks are required if the MA is not the destination (parent) public key, and merely selects a + migration destination: (1) sigTicket must prove that restrictTicket was signed by the MA; (2) + restrictTicket must vouch that the target public key is approved for migration to the destination + (parent) public key. (Obviously, this more complex method may also be used by an MA to approve + migration to that MA.) In both cases, the MA must be one of the MAs implicitly listed in the + migrationAuth of the target key-to-be-migrated. + + When the migrationType is TPM_MS_RESTRICT_MIGRATE, restrictTicket and sigTicket are unused. The + TPM may test that the corresponding sizes are zero, so the caller should set them to zero for + interoperability. +*/ + +TPM_RESULT TPM_Process_CMK_CreateBlob(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 that can decrypt encData. */ + TPM_MIGRATE_SCHEME migrationType; /* The migration type, either TPM_MS_RESTRICT_MIGRATE or + TPM_MS_RESTRICT_APPROVE + NOTE Never used */ + TPM_MIGRATIONKEYAUTH migrationKeyAuth; /* Migration public key and its authorization + session digest. */ + TPM_DIGEST pubSourceKeyDigest; /* The digest of the TPM_PUBKEY of the entity to be migrated + */ + TPM_SIZED_BUFFER msaListBuffer; /* One or more digests of public keys belonging to migration + authorities */ + TPM_SIZED_BUFFER restrictTicketBuffer; /* If migrationType is TPM_MS_RESTRICT_APPROVE, a + TPM_CMK_AUTH structure, containing the digests of + the public keys belonging to the Migration + Authority, the destination parent key and the + key-to-be-migrated. */ + TPM_SIZED_BUFFER sigTicketBuffer; /* If migrationType is TPM_MS_RESTRICT_APPROVE, a TPM_HMAC + structure, generated by the TPM, signaling a valid + signature over restrictTicket */ + 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; /* Continue use flag for parent session */ + TPM_AUTHDATA parentAuth; /* The authorization 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_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; /* decryption of encData */ + uint32_t d1DecryptLength = 0; /* actual valid data */ + TPM_STORE_ASYMKEY d1AsymKey; /* structure from decrypted encData */ + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_STORE_BUFFER mka_sbuffer; /* serialized migrationKeyAuth.migrationKey */ + const unsigned char *mka_buffer; + uint32_t mka_length; + TPM_DIGEST migrationKeyDigest; /* digest of migrationKeyAuth.migrationKey */ + TPM_DIGEST pHash; + TPM_CMK_MIGAUTH m2CmkMigauth; + TPM_BOOL valid; + TPM_MSA_COMPOSITE msaList; + TPM_DIGEST sigTicket; + TPM_CMK_AUTH restrictTicket; + TPM_CMK_SIGTICKET v1CmkSigticket; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* String used for xor encryption */ + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + + printf("TPM_Process_CMK_CreateBlob: Ordinal Entry\n"); + d1Decrypt = NULL; /* freed @1 */ + TPM_Migrationkeyauth_Init(&migrationKeyAuth); /* freed @2 */ + TPM_SizedBuffer_Init(&msaListBuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&restrictTicketBuffer); /* freed @4 */ + TPM_SizedBuffer_Init(&sigTicketBuffer); /* freed @5 */ + TPM_SizedBuffer_Init(&encData); /* freed @6 */ + TPM_SizedBuffer_Init(&random); /* freed @7 */ + TPM_SizedBuffer_Init(&outData); /* freed @8 */ + TPM_Sbuffer_Init(&mka_sbuffer); /* freed @9 */ + TPM_StoreAsymkey_Init(&d1AsymKey); /* freed @10 */ + TPM_MsaComposite_Init(&msaList); /* freed @11 */ + TPM_CmkAuth_Init(&restrictTicket); /* freed @12 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @13 */ + TPM_CmkSigticket_Init(&v1CmkSigticket); /* freed @14 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&migrationType, &command, ¶mSize); + } + /* get migrationKeyAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, ¶mSize); + } + /* get pubSourceKeyDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(pubSourceKeyDigest, &command, ¶mSize); + } + /* get msaListBuffer */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, ¶mSize); + } + /* deserialize to msaList */ + if (returnCode == TPM_SUCCESS) { + stream = msaListBuffer.buffer; + stream_size = msaListBuffer.size; + returnCode = TPM_MsaComposite_Load(&msaList, &stream, &stream_size); + } + /* get restrictTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&restrictTicketBuffer, &command, ¶mSize); + } + /* get sigTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&sigTicketBuffer, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &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(&parentAuthHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* + The TPM does not check the PCR values when migrating values locked to a PCR. */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* do not check PCR's */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + parentAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate that parentAuth authorizes the use of the key pointed to by parentHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2.The TPM MAY verify that migrationType == migrationKeyAuth -> migrationScheme and return + TPM_BAD_MODE on error. + a.The TPM MAY ignore migrationType. */ + /* 3. Verify that parentHandle-> keyFlags-> migratable == FALSE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_CreateBlob: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 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_CMK_CreateBlob: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Create d1 by decrypting encData using the key pointed to by parentHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Decrypting encData\n"); + /* decrypt with the parent key to a stream */ + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data, freed @1 */ + &d1DecryptLength, /* actual size of d1 data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + /* deserialize the stream to a TPM_STORE_ASYMKEY d1AsymKey */ + if (returnCode == TPM_SUCCESS) { + stream = d1Decrypt; + stream_size = d1DecryptLength; + returnCode = TPM_StoreAsymkey_Load(&d1AsymKey, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* 5. Verify that the digest within migrationKeyAuth is legal for this TPM and public key */ + /* NOTE Presumably, this reverses the steps from TPM_AuthorizeMigrationKey */ + /* create h1 by concatenating (migrationKey || migrationScheme || TPM_PERMANENT_DATA -> + tpmProof) */ + /* first serialize the TPM_PUBKEY migrationKeyAuth -> migrationKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Verifying migrationKeyAuth\n"); + returnCode = TPM_Pubkey_Store(&mka_sbuffer, &(migrationKeyAuth.migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialization result */ + TPM_Sbuffer_Get(&mka_sbuffer, &mka_buffer, &mka_length); + /* then create the hash. tpmProof indicates that the input knew ownerAuth in + TPM_AuthorizeMigrationKey */ + /* compare to migrationKeyAuth -> digest */ + returnCode = TPM_SHA1_Check(migrationKeyAuth.digest, + mka_length, mka_buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationKeyAuth.migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* 6. Verify that d1 -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ + if (returnCode == TPM_SUCCESS) { + if ((d1AsymKey.payload != TPM_PT_MIGRATE_RESTRICTED) && + (d1AsymKey.payload != TPM_PT_MIGRATE_EXTERNAL)) { + printf("TPM_Process_CMK_CreateBlob: Error, invalid payload %02x\n", d1AsymKey.payload); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* 7. Verify that the migration authorities in msaList are authorized to migrate this key */ + /* a. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* i. Set M2 -> msaDigest to SHA-1[msaList] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkMigauth.msaDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set M2 -> pubKeyDigest to pubSourceKeyDigest */ + TPM_Digest_Copy(m2CmkMigauth.pubKeyDigest, pubSourceKeyDigest); + /* b. Verify that d1 -> migrationAuth == HMAC(M2) using tpmProof as the secret and return + error TPM_MA_AUTHORITY on mismatch */ + returnCode = TPM_CmkMigauth_CheckHMAC(&valid, + d1AsymKey.migrationAuth, /* expected */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key*/ + &m2CmkMigauth); + if (!valid) { + printf("TPM_Process_CMK_CreateBlob: Error validating migrationAuth\n"); + returnCode = TPM_MA_AUTHORITY; + } + } + /* SHA-1[migrationKeyAuth -> migrationKey] is required below */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(migrationKeyDigest, + mka_length, mka_buffer, /* serialized migrationKey */ + 0, NULL); + } + /* 8. If migrationKeyAuth -> migrationScheme == TPM_MS_RESTRICT_MIGRATE */ + if ((returnCode == TPM_SUCCESS) && + (migrationKeyAuth.migrationScheme == TPM_MS_RESTRICT_MIGRATE)) { + /* a. Verify that intended migration destination is an MA: */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: migrationScheme is TPM_MS_RESTRICT_MIGRATE\n"); + /* i. For one of n=1 to n=(msaList -> MSAlist), verify that SHA-1[migrationKeyAuth -> + migrationKey] == msaList -> migAuthDigest[n] */ + returnCode = TPM_MsaComposite_CheckMigAuthDigest(migrationKeyDigest, &msaList); + } + /* b. Validate that the MA key is the correct type */ + /* i. Validate that migrationKeyAuth -> migrationKey -> algorithmParms -> algorithmID == + TPM_ALG_RSA */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CMK_CreateBlob: Error, algorithmID %08x not TPM_ALG_RSA\n", + migrationKeyAuth.migrationKey.algorithmParms.algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* ii. Validate that migrationKeyAuth -> migrationKey -> algorithmParms -> encScheme is an + encryption scheme supported by the TPM */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.encScheme != + TPM_ES_RSAESOAEP_SHA1_MGF1) { + + printf("TPM_Process_CMK_CreateBlob: Error, " + "encScheme %04hx not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + migrationKeyAuth.migrationKey.algorithmParms.encScheme ); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* iii. Validate that migrationKeyAuth -> migrationKey ->algorithmParms -> sigScheme is + TPM_SS_NONE */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.sigScheme != TPM_SS_NONE) { + printf("TPM_Process_CMK_CreateBlob: Error, sigScheme %04hx not TPM_SS_NONE\n", + migrationKeyAuth.migrationKey.algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* c. The TPM MAY validate that restrictTicketSize is zero. */ + if (returnCode == TPM_SUCCESS) { + if (restrictTicketBuffer.size != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, " + "TPM_MS_RESTRICT_MIGRATE and restrictTicketSize %u not zero\n", + restrictTicketBuffer.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. The TPM MAY validate that sigTicketSize is zero. */ + if (returnCode == TPM_SUCCESS) { + if (sigTicketBuffer.size != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, " + "TPM_MS_RESTRICT_MIGRATE and sigTicketSize %u not zero\n", + sigTicketBuffer.size); + returnCode = TPM_BAD_PARAMETER; + } + } + } + /* 9. If migrationKeyAuth -> migrationScheme == TPM_MS_RESTRICT_APPROVE */ + else if ((returnCode == TPM_SUCCESS) && + (migrationKeyAuth.migrationScheme == TPM_MS_RESTRICT_APPROVE)) { + /* a. Verify that the intended migration destination has been approved by the MSA: */ + /* i. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: */ + /* (1) V1 -> verKeyDigest = msaList -> migAuthDigest[n] */ + /* (2) V1 -> signedData = SHA-1[restrictTicket] */ + printf("TPM_Process_CMK_CreateBlob: migrationScheme is TPM_MS_RESTRICT_APPROVE_DOUBLE\n"); + /* deserialize the sigTicket TPM_HMAC */ + if (returnCode == TPM_SUCCESS) { + stream = sigTicketBuffer.buffer; + stream_size = sigTicketBuffer.size; + returnCode = TPM_Digest_Load(sigTicket, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(v1CmkSigticket.signedData, + restrictTicketBuffer.size, restrictTicketBuffer.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_MsaComposite_CheckSigTicket(sigTicket, + tpm_state->tpm_permanent_data.tpmProof, + &msaList, + &v1CmkSigticket); + } + /* ii. If [restrictTicket -> destinationKeyDigest] != SHA-1[migrationKeyAuth -> + migrationKey], return error TPM_MA_DESTINATION */ + /* deserialize the restrictTicket structure */ + if (returnCode == TPM_SUCCESS) { + stream = restrictTicketBuffer.buffer; + stream_size = restrictTicketBuffer.size; + returnCode = TPM_CmkAuth_Load(&restrictTicket, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(migrationKeyDigest, + restrictTicket.destinationKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, no match to destinationKeyDigest\n"); + returnCode = TPM_MA_DESTINATION; + } + } + /* iii. If [restrictTicket -> sourceKeyDigest] != pubSourceKeyDigest, return error + TPM_MA_SOURCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(pubSourceKeyDigest, restrictTicket.sourceKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, no match to sourceKeyDigest\n"); + returnCode = TPM_MA_SOURCE; + } + } + } + /* 10. Else return with error TPM_BAD_PARAMETER. */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, Illegal migrationScheme %04hx\n", + migrationKeyAuth.migrationScheme); + returnCode = TPM_BAD_PARAMETER; + } + /* 11. Build two bytes array, K1 and K2, using d1: */ + /* a. K1 = TPM_STORE_ASYMKEY.privKey[0..19] (TPM_STORE_ASYMKEY.privKey.keyLength + 16 bytes of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K1) = 20 */ + /* b. K2 = TPM_STORE_ASYMKEY.privKey[20..131] (position 16-127 of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K2) = 112 */ + /* 12. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* a. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_CMK_MIGRATE */ + /* b. TPM_MIGRATE_ASYMKEY.usageAuth = TPM_STORE_ASYMKEY.usageAuth */ + /* c. TPM_MIGRATE_ASYMKEY.pubDataDigest = TPM_STORE_ASYMKEY.pubDataDigest */ + /* d. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* e. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + /* 13. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters m, pHash, and seed */ + /* a. m is the previously created M1 */ + /* b. pHash = SHA-1( SHA-1[msaList] || pubSourceKeyDigest) */ + /* c. seed = s1 = the previously created K1 */ + /* 14. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of o1. Return + r1 in the */ + /* random parameter */ + /* 15. Create x1 by XOR of o1 with r1 */ + /* 16. Copy r1 into the output field "random" */ + /* 17. Encrypt x1 with the migrationKeyAuth-> migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(pHash, + TPM_DIGEST_SIZE, m2CmkMigauth.msaDigest, + TPM_DIGEST_SIZE, pubSourceKeyDigest, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateBlobCommon(&outData, + &d1AsymKey, + pHash, + TPM_PT_CMK_MIGRATE, + &random, + &(migrationKeyAuth.migrationKey)); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateBlob: 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 random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return outData */ + 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, + *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, + parentAuthHandle); + } + /* + cleanup + */ + free(d1Decrypt); /* @1 */ + TPM_Migrationkeyauth_Delete(&migrationKeyAuth); /* @2 */ + TPM_SizedBuffer_Delete(&msaListBuffer); /* @3 */ + TPM_SizedBuffer_Delete(&restrictTicketBuffer); /* @4 */ + TPM_SizedBuffer_Delete(&sigTicketBuffer); /* @5 */ + TPM_SizedBuffer_Delete(&encData); /* @6 */ + TPM_SizedBuffer_Delete(&random); /* @7 */ + TPM_SizedBuffer_Delete(&outData); /* @8 */ + TPM_Sbuffer_Delete(&mka_sbuffer); /* @9 */ + TPM_StoreAsymkey_Delete(&d1AsymKey); /* @10 */ + TPM_MsaComposite_Delete(&msaList); /* @11 */ + TPM_CmkAuth_Delete(&restrictTicket); /* @12 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @13 */ + TPM_CmkSigticket_Delete(&v1CmkSigticket); /* @14 */ + return rcf; +} + +/* 11.7 TPM_CMK_SetRestrictions rev 96 + + This command is used by the Owner to dictate the usage of a certified-migration key with + delegated authorisation (authorisation other than actual Owner authorisation). + + This command is provided for privacy reasons and must not itself be delegated, because a + certified-migration-key may involve a contractual relationship between the Owner and an external + entity. + + Since restrictions are validated at DSAP session use, there is no need to invalidate DSAP + sessions when the restriction value changes. +*/ + +TPM_RESULT TPM_Process_CMK_SetRestrictions(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_CMK_DELEGATE restriction; /* The bit mask of how to set the restrictions on CMK keys + */ + TPM_AUTHHANDLE authHandle; /* The authorization handle TPM Owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest. HMAC key: TPM Owner Auth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_CMK_SetRestrictions: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get restriction */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&restriction, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_SetRestrictions: restriction %08x\n", restriction); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_SetRestrictions: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the ordinal and parameters using TPM Owner authorization, return TPM_AUTHFAIL on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CMK_SetRestrictions: ownerAuth secret", *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Set TPM_PERMANENT_DATA -> TPM_CMK_DELEGATE -> restrictDelegate = restriction */ + if (returnCode == TPM_SUCCESS) { + /* only update NVRAM if the value is changing */ + if (tpm_state->tpm_permanent_data.restrictDelegate != restriction) { + tpm_state->tpm_permanent_data.restrictDelegate = restriction; + /* Store the permanent data back to NVRAM */ + printf("TPM_Process_CMK_SetRestrictions: Storing permanent data\n"); + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + else { + printf("TPM_Process_CMK_SetRestrictions: No change to value\n"); + } + } + /* 3. Return TPM_SUCCESS */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_SetRestrictions: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 11.6 TPM_CMK_ApproveMA 87 + + This command creates an authorization ticket, to allow the TPM owner to specify which Migration + Authorities they approve and allow users to create certified-migration-keys without further + involvement with the TPM owner. + + It is the responsibility of the TPM Owner to determine whether a particular Migration Authority is + suitable to control migration. +*/ + +TPM_RESULT TPM_Process_CMK_ApproveMA(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_DIGEST migrationAuthorityDigest; /* A digest of a TPM_MSA_COMPOSITE structure (itself + one or more digests of public keys belonging to + migration authorities) */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization HMAC, key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_CMK_MA_APPROVAL m2CmkMaApproval; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_HMAC outData; /* HMAC of migrationAuthorityDigest */ + + printf("TPM_Process_CMK_ApproveMA: Ordinal Entry\n"); + TPM_CmkMaApproval_Init(&m2CmkMaApproval); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationAuthorityDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityDigest, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_ApproveMA: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to use the TPM by the TPM Owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 2. Create M2 a TPM_CMK_MA_APPROVAL structure */ + /* NOTE Done by TPM_CmkMaApproval_Init() */ + /* a. Set M2 ->migrationAuthorityDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m2CmkMaApproval.migrationAuthorityDigest, migrationAuthorityDigest); + /* 3. Set outData = HMAC(M2) using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (outData, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMaApproval, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMaApproval_Store); /* store function */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_ApproveMA: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + returnCode = TPM_Digest_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, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_CmkMaApproval_Delete(&m2CmkMaApproval); /* @1 */ + return rcf; +} + +/* 11.10 TPM_CMK_ConvertMigration rev 106 + + TPM_CMK_ConvertMigration completes the migration of certified migration blobs. + + This command takes a certified migration blob and creates a normal wrapped blob with payload type + TPM_PT_MIGRATE_EXTERNAL. The migrated blob must be loaded into the TPM using the normal + TPM_LoadKey function. + + Note that the command migrates private keys, only. The migration of the associated public keys is + not specified by TPM because they are not security sensitive. Migration of the associated public + keys may be specified in a platform specific specification. A TPM_KEY structure must be recreated + before the migrated key can be used by the target TPM in a LoadKey command. + + TPM_CMK_ConvertMigration checks that one of the MAs implicitly listed in the migrationAuth of the + target key has approved migration of the target key to the destination (parent) key, and that the + settings (flags etc.) in the target key are those of a CMK. +*/ + +TPM_RESULT TPM_Process_CMK_ConvertMigration(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 a loaded key that can decrypt keys. */ + TPM_CMK_AUTH restrictTicket; /* The digests of public keys belonging to the Migration + Authority, the destination parent key and the + key-to-be-migrated. */ + TPM_HMAC sigTicket; /* A signature ticket, generated by the TPM, signaling a + valid signature over restrictTicket */ + TPM_KEY migratedKey; /* The public key of the key-to-be-migrated. The private + portion MUST be TPM_MIGRATE_ASYMKEY properly XOR'd */ + TPM_SIZED_BUFFER msaListBuffer; /* One or more digests of public keys belonging to migration + authorities */ + TPM_SIZED_BUFFER random; /* Random value used to hide key data. */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA parentAuth; /* Authorization HMAC: 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_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; + uint32_t d1DecryptLength = 0; /* actual valid data */ + BYTE *o1Oaep; + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_MSA_COMPOSITE msaList; + TPM_DIGEST msaListDigest; + TPM_DIGEST migratedPubKeyDigest; + TPM_STORE_ASYMKEY d2AsymKey; + TPM_STORE_BUFFER d2_sbuffer; + TPM_DIGEST parentPubKeyDigest; + TPM_CMK_SIGTICKET v1CmkSigticket; + TPM_CMK_MIGAUTH m2CmkMigauth; + + /* 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 encrypted private key that can be loaded with + TPM_LoadKey */ + + printf("TPM_Process_CMK_ConvertMigration: Ordinal Entry\n"); + TPM_CmkAuth_Init(&restrictTicket); /* freed @1 */ + TPM_Key_Init(&migratedKey); /* freed @2 */ + TPM_SizedBuffer_Init(&msaListBuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&random); /* freed @4 */ + TPM_SizedBuffer_Init(&outData); /* freed @5 */ + d1Decrypt = NULL; /* freed @6 */ + TPM_MsaComposite_Init(&msaList); /* freed @7 */ + TPM_StoreAsymkey_Init(&d2AsymKey); /* freed @8 */ + TPM_Sbuffer_Init(&d2_sbuffer); /* freed @9 */ + TPM_CmkSigticket_Init(&v1CmkSigticket); /* freed @10 */ + o1Oaep = NULL; /* freed @11 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @12 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get restrictTicket */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: parentHandle %08x\n", parentHandle); + returnCode = TPM_CmkAuth_Load(&restrictTicket, &command, ¶mSize); + } + /* get sigTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(sigTicket, &command, ¶mSize); + } + /* get migratedKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&migratedKey, &command, ¶mSize); + } + /* get msaListBuffer */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, ¶mSize); + } + /* get random */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&random, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_ConvertMigration: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to use the key in parentHandle */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using private key */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If the keyUsage field of the key referenced by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CMK_ConvertMigration: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 by decrypting the migratedKey -> encData area using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Decrypting encData\n"); + TPM_PrintFour("TPM_Process_CMK_ConvertMigration: encData", migratedKey.encData.buffer); + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + migratedKey.encData.buffer, /* encrypted data */ + migratedKey.encData.size, + parentKey); + } + /* the random input parameter must be the same length as the decrypted data */ + if (returnCode == TPM_SUCCESS) { + if (d1DecryptLength != random.size) { + printf("TPM_Process_CMK_ConvertMigration: Error " + "decrypt data length %u random size %u\n", + d1DecryptLength, random.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* allocate memory for o1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: d1 length %u\n", d1DecryptLength); + TPM_PrintFour("TPM_Process_CMK_ConvertMigration: d1 -", d1Decrypt); + /* 4. Create o1 by XOR d1 and random parameter */ + TPM_XOR(o1Oaep, d1Decrypt, random.buffer, d1DecryptLength); + /* 5. Create m1 a TPM_MIGRATE_ASYMKEY, seed and pHash by OAEP decoding o1 */ + /* 7. Create k1 by combining seed and the TPM_MIGRATE_ASYMKEY -> partPrivKey */ + /* 8. Create d2 a TPM_STORE_ASYMKEY structure */ + /* a. Set the TPM_STORE_ASYMKEY -> privKey field to k1 */ + /* b. Set d2 -> usageAuth to m1 -> usageAuth */ + /* c. Set d2 -> pubDataDigest to m1 -> pubDataDigest */ + returnCode = TPM_StoreAsymkey_LoadO1(&d2AsymKey, o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking pHash\n"); + /* 6. Create migratedPubKey a TPM_PUBKEY structure corresponding to migratedKey */ + /* NOTE this function goes directly to the SHA1 digest */ + returnCode = TPM_Key_GeneratePubkeyDigest(migratedPubKeyDigest, &migratedKey); + } + /* 6.a. Verify that pHash == SHA-1( SHA-1[msaList] || SHA-1(migratedPubKey ) */ + /* deserialize to msaListBuffer to msaList */ + if (returnCode == TPM_SUCCESS) { + stream = msaListBuffer.buffer; + stream_size = msaListBuffer.size; + returnCode = TPM_MsaComposite_Load(&msaList, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(msaListDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + /* pHash is returned in TPM_STORE_ASYMKEY -> migrationAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_Check(d2AsymKey.migrationAuth, + TPM_DIGEST_SIZE, msaListDigest, + TPM_DIGEST_SIZE, migratedPubKeyDigest, + 0, NULL); + } + /* 9. Verify that parentHandle-> keyFlags -> migratable == FALSE and parentHandle-> encData -> + migrationAuth == tpmProof */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking parent key\n"); + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_ConvertMigration: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 10. Verify that m1 -> payload == TPM_PT_CMK_MIGRATE, then set d2-> payload = + TPM_PT_MIGRATE_EXTERNAL */ + /* NOTE TPM_StoreAsymkey_LoadO1() copied TPM_MIGRATE_ASYMKEY -> payload to TPM_STORE_ASYMKEY -> + payload */ + if (returnCode == TPM_SUCCESS) { + if (d2AsymKey.payload != TPM_PT_CMK_MIGRATE) { + printf("TPM_Process_CMK_ConvertMigration: Error, invalid payload %02x\n", + d2AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + else { + d2AsymKey.payload = TPM_PT_MIGRATE_EXTERNAL; + } + } + /* 11. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: */ + /* a. V1 -> verKeyDigest = msaList -> migAuthDigest[n] */ + /* b. V1 -> signedData = SHA-1[restrictTicket] */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking sigTicket\n"); + /* generate SHA1[restrictTicket] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(v1CmkSigticket.signedData, &restrictTicket, + (TPM_STORE_FUNCTION_T)TPM_CmkAuth_Store); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_CMK_ConvertMigration: TPM_CMK_SIGTICKET -> sigTicket", + v1CmkSigticket.signedData); + returnCode = TPM_MsaComposite_CheckSigTicket(sigTicket, + tpm_state->tpm_permanent_data.tpmProof, + &msaList, + &v1CmkSigticket); + } + } + /* 12. Create parentPubKey, a TPM_PUBKEY structure corresponding to parenthandle */ + if (returnCode == TPM_SUCCESS) { + /* NOTE this function goes directly to the SHA1 digest */ + returnCode = TPM_Key_GeneratePubkeyDigest(parentPubKeyDigest, parentKey); + } + /* 13. If [restrictTicket -> destinationKeyDigest] != SHA-1(parentPubKey), return error + TPM_MA_DESTINATION */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(restrictTicket.destinationKeyDigest, + parentPubKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Error checking destinationKeyDigest\n"); + returnCode = TPM_MA_DESTINATION; + } + } + /* 14. Verify that migratedKey is corresponding to d2 */ + /* NOTE check the private key against the public key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StorePrivkey_Convert(&d2AsymKey, + &(migratedKey.algorithmParms), + &(migratedKey.pubKey)); + } + /* 15. If migratedKey -> keyFlags -> migratable is FALSE, and return error TPM_INVALID_KEYUSAGE + */ + if (returnCode == TPM_SUCCESS) { + if (!(migratedKey.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CMK_ConvertMigration: Error, migratedKey migratable is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 16. If migratedKey -> keyFlags -> migrateAuthority is FALSE, return error + TPM_INVALID_KEYUSAGE + */ + if (returnCode == TPM_SUCCESS) { + if (!(migratedKey.keyFlags & TPM_MIGRATEAUTHORITY)) { + printf("TPM_Process_CMK_ConvertMigration: Error, " + "migratedKey migrateauthority is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 17. If [restrictTicket -> sourceKeyDigest] != SHA-1(migratedPubKey), return error + TPM_MA_SOURCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(restrictTicket.sourceKeyDigest, migratedPubKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Error checking sourceKeyDigest\n"); + returnCode = TPM_MA_SOURCE; + } + } + /* 18. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* a. Set M2 -> msaDigest to SHA-1[msaList] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkMigauth.msaDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + if (returnCode == TPM_SUCCESS) { + /* b. Set M2 -> pubKeyDigest to SHA-1[migratedPubKey] */ + TPM_Digest_Copy(m2CmkMigauth.pubKeyDigest, migratedPubKeyDigest); + /* 19. Set d2 -> migrationAuth = HMAC(M2) using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (d2AsymKey.migrationAuth, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMigauth_Store); /* store function */ + } + /* 21. Create outData using the key in parentHandle to perform the encryption */ + if (returnCode == TPM_SUCCESS) { + /* serialize d2Asymkey to d2_sbuffer */ + returnCode = TPM_StoreAsymkey_Store(&d2_sbuffer, FALSE, &d2AsymKey); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncryptSbuffer_Key(&outData, &d2_sbuffer, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_ConvertMigration: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + 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, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_CmkAuth_Delete(&restrictTicket); /* @1 */ + TPM_Key_Delete(&migratedKey); /* @2 */ + TPM_SizedBuffer_Delete(&msaListBuffer); /* @3 */ + TPM_SizedBuffer_Delete(&random); /* @4 */ + TPM_SizedBuffer_Delete(&outData); /* @5 */ + free(d1Decrypt); /* @6 */ + TPM_MsaComposite_Delete(&msaList); /* @7 */ + TPM_StoreAsymkey_Delete(&d2AsymKey); /* @8 */ + TPM_Sbuffer_Delete(&d2_sbuffer); /* @9 */ + TPM_CmkSigticket_Delete(&v1CmkSigticket); /* @10 */ + free(o1Oaep); /* @11 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @12 */ + return rcf; +} diff --git a/src/tpm12/tpm_migration.h b/src/tpm12/tpm_migration.h new file mode 100644 index 0000000..91f9fa3 --- /dev/null +++ b/src/tpm12/tpm_migration.h @@ -0,0 +1,218 @@ +/********************************************************************************/ +/* */ +/* Migration */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_migration.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_MIGRATION_H +#define TPM_MIGRATION_H + +#include "tpm_global.h" + +/* + TPM_MIGRATIONKEYAUTH +*/ + +void TPM_Migrationkeyauth_Init(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); +TPM_RESULT TPM_Migrationkeyauth_Load(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Migrationkeyauth_Store(TPM_STORE_BUFFER *sbuffer, + TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); +void TPM_Migrationkeyauth_Delete(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); + +/* + TPM_MSA_COMPOSITE +*/ + +void TPM_MsaComposite_Init(TPM_MSA_COMPOSITE *tpm_msa_composite); +TPM_RESULT TPM_MsaComposite_Load(TPM_MSA_COMPOSITE *tpm_msa_composite, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_MsaComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MSA_COMPOSITE *tpm_msa_composite); +void TPM_MsaComposite_Delete(TPM_MSA_COMPOSITE *tpm_msa_composite); + +TPM_RESULT TPM_MsaComposite_CheckMigAuthDigest(TPM_DIGEST tpm_digest, + TPM_MSA_COMPOSITE *tpm_msa_composite); +TPM_RESULT TPM_MsaComposite_CheckSigTicket(TPM_DIGEST sigTicket, + TPM_SECRET tpmProof, + TPM_MSA_COMPOSITE *tpm_msa_composite, + TPM_CMK_SIGTICKET *tpm_cmk_sigticket); + +/* + TPM_CMK_AUTH +*/ + +void TPM_CmkAuth_Init(TPM_CMK_AUTH *tpm_cmk_auth); +TPM_RESULT TPM_CmkAuth_Load(TPM_CMK_AUTH *tpm_cmk_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_AUTH *tpm_cmk_auth); +void TPM_CmkAuth_Delete(TPM_CMK_AUTH *tpm_cmk_auth); + +/* + TPM_CMK_MIGAUTH +*/ + +void TPM_CmkMigauth_Init(TPM_CMK_MIGAUTH *tpm_cmk_migauth); +TPM_RESULT TPM_CmkMigauth_Load(TPM_CMK_MIGAUTH *tpm_cmk_migauth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkMigauth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MIGAUTH *tpm_cmk_migauth); +void TPM_CmkMigauth_Delete(TPM_CMK_MIGAUTH *tpm_cmk_migauth); + +TPM_RESULT TPM_CmkMigauth_CheckHMAC(TPM_BOOL *valid, + TPM_HMAC tpm_hmac, + TPM_SECRET tpm_hmac_key, + TPM_CMK_MIGAUTH *tpm_cmk_migauth); + +/* + TPM_CMK_SIGTICKET +*/ + +void TPM_CmkSigticket_Init(TPM_CMK_SIGTICKET *tpm_cmk_sigticket); +TPM_RESULT TPM_CmkSigticket_Load(TPM_CMK_SIGTICKET *tpm_cmk_sigticket, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkSigticket_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_SIGTICKET *tpm_cmk_sigticket); +void TPM_CmkSigticket_Delete(TPM_CMK_SIGTICKET *tpm_cmk_sigticket); + +/* + TPM_CMK_MA_APPROVAL +*/ + +void TPM_CmkMaApproval_Init(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); +TPM_RESULT TPM_CmkMaApproval_Load(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkMaApproval_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); +void TPM_CmkMaApproval_Delete(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); + +TPM_RESULT TPM_CmkMaApproval_CheckHMAC(TPM_BOOL *valid, + TPM_HMAC tpm_hmac, + TPM_SECRET tpm_hmac_key, + TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_CreateBlobCommon(TPM_SIZED_BUFFER *outData, + TPM_STORE_ASYMKEY *d1Key, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SIZED_BUFFER *random, + TPM_PUBKEY *migrationKey); + +TPM_RESULT TPM_Process_CreateMigrationBlob(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 TPM_Process_ConvertMigrationBlob(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 TPM_Process_AuthorizeMigrationKey(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 TPM_Process_MigrateKey(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 TPM_Process_CMK_CreateKey(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 TPM_Process_CMK_CreateTicket(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 TPM_Process_CMK_CreateBlob(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 TPM_Process_CMK_SetRestrictions(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 TPM_Process_CMK_ApproveMA(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 TPM_Process_CMK_ConvertMigration(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); + + + +#endif diff --git a/src/tpm12/tpm_nonce.c b/src/tpm12/tpm_nonce.c new file mode 100644 index 0000000..115bef6 --- /dev/null +++ b/src/tpm12/tpm_nonce.c @@ -0,0 +1,157 @@ +/********************************************************************************/ +/* */ +/* Nonce Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nonce.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_nonce.h" + +/* TPM_Nonce_Init resets a nonce structure to zeros */ + +void TPM_Nonce_Init(TPM_NONCE tpm_nonce) +{ + size_t i; + + printf(" TPM_Nonce_Init:\n"); + for (i = 0 ; i < TPM_NONCE_SIZE ; i++) { + tpm_nonce[i] = 0; + } + return; +} + +/* TPM_Nonce_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + + +TPM_RESULT TPM_Nonce_Load(TPM_NONCE tpm_nonce, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Load:\n"); + rc = TPM_Loadn(tpm_nonce, TPM_NONCE_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Nonce_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_Nonce_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NONCE tpm_nonce) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_nonce, TPM_NONCE_SIZE); + return rc; +} + +/* TPM_Nonce_Copy() copies the source to the destination + */ + +void TPM_Nonce_Copy(TPM_NONCE destination, const TPM_NONCE source) +{ + printf(" TPM_Nonce_Copy:\n"); + memcpy(destination, source, TPM_NONCE_SIZE); + return; +} + +/* TPM_Nonce_Compare() compares the source to the destination. + + Returns TPM_AUTHFAIL if the nonces are not equal +*/ + +TPM_RESULT TPM_Nonce_Compare(TPM_NONCE expect, const TPM_NONCE actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Compare:\n"); + rc = memcmp(expect, actual, TPM_NONCE_SIZE); + if (rc != 0) { + printf("TPM_Nonce_Compare: Error comparing nonce\n"); + TPM_PrintFour(" TPM_Nonce_Compare: Expect", expect); + TPM_PrintFour(" TPM_Nonce_Compare: Actual", actual); + rc = TPM_AUTHFAIL; + } + return rc; +} + +/* TPM_Nonce_Generate() generates a new nonce from the random number generator + */ + +TPM_RESULT TPM_Nonce_Generate(TPM_NONCE tpm_nonce) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Generate:\n"); + rc = TPM_Random(tpm_nonce, TPM_NONCE_SIZE); + return rc; +} + +/* TPM_Nonce_IsZero() returns 'isZero' TRUE is all bytes 'tpm_nonce' are 0x00 + */ + +void TPM_Nonce_IsZero(TPM_BOOL *isZero, TPM_NONCE tpm_nonce) +{ + size_t i; + + printf(" TPM_Nonce_IsZero:\n"); + for (i = 0, *isZero = TRUE ; (i < TPM_NONCE_SIZE) && *isZero ; i++) { + if (tpm_nonce[i] != 0) { + *isZero = FALSE; + } + } + return; +} + diff --git a/src/tpm12/tpm_nonce.h b/src/tpm12/tpm_nonce.h new file mode 100644 index 0000000..a2113f8 --- /dev/null +++ b/src/tpm12/tpm_nonce.h @@ -0,0 +1,60 @@ +/********************************************************************************/ +/* */ +/* Nonce Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nonce.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_NONCE_H +#define TPM_NONCE_H + +#include "tpm_store.h" +#include "tpm_structures.h" + +void TPM_Nonce_Init(TPM_NONCE tpm_nonce); + +TPM_RESULT TPM_Nonce_Generate(TPM_NONCE tpm_nonce); + +void TPM_Nonce_Copy(TPM_NONCE destination, + const TPM_NONCE source); +TPM_RESULT TPM_Nonce_Load(TPM_NONCE tpm_nonce, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Nonce_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NONCE tpm_nonce); +TPM_RESULT TPM_Nonce_Compare(TPM_NONCE expect, const TPM_NONCE actual); +void TPM_Nonce_IsZero(TPM_BOOL *isZero, TPM_NONCE tpm_nonce); + +#endif diff --git a/src/tpm12/tpm_nvram.c b/src/tpm12/tpm_nvram.c new file mode 100644 index 0000000..1235973 --- /dev/null +++ b/src/tpm12/tpm_nvram.c @@ -0,0 +1,3747 @@ +/********************************************************************************/ +/* */ +/* NVRAM Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram.c 4724 2014-08-11 20:33:23Z 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 <errno.h> + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_nvfile.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_structures.h" + +#include "tpm_nvram.h" + +/* + NV Defined Space Utilities +*/ + +/* + TPM_NV_ATTRIBUTES +*/ + +/* TPM_NVAttributes_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVAttributes_Init(TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + printf(" TPM_NVAttributes_Init:\n"); + tpm_nv_attributes->attributes = 0; + return; +} + +/* TPM_NVAttributes_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVAttributes_Init() + After use, call TPM_NVAttributes_Delete() to free memory +*/ + +TPM_RESULT TPM_NVAttributes_Load(TPM_NV_ATTRIBUTES *tpm_nv_attributes, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVAttributes_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_ATTRIBUTES, stream, stream_size); + } + /* load attributes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_attributes->attributes), stream, stream_size); + } + return rc; +} + +/* TPM_NVAttributes_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_NVAttributes_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVAttributes_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_ATTRIBUTES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_attributes->attributes); + } + return rc; +} + +/* TPM_NVAttributes_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the nv_attributes + sets pointers to NULL + calls TPM_NVAttributes_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVAttributes_Delete(TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + printf(" TPM_NVAttributes_Delete:\n"); + if (tpm_nv_attributes != NULL) { + TPM_NVAttributes_Init(tpm_nv_attributes); + } + return; +} + +void TPM_NVAttributes_Copy(TPM_NV_ATTRIBUTES *tpm_nv_attributes_dest, + TPM_NV_ATTRIBUTES *tpm_nv_attributes_src) +{ + tpm_nv_attributes_dest->attributes = tpm_nv_attributes_src->attributes; + return; +} + +/* + TPM_NV_DATA_PUBLIC +*/ + +/* TPM_NVDataPublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVDataPublic_Init(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) +{ + printf(" TPM_NVDataPublic_Init:\n"); + tpm_nv_data_public->nvIndex = TPM_NV_INDEX_LOCK; /* mark unused */ + TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoRead)); + TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoWrite)); + TPM_NVAttributes_Init(&(tpm_nv_data_public->permission)); + tpm_nv_data_public->bReadSTClear = FALSE; + tpm_nv_data_public->bWriteSTClear = FALSE; + tpm_nv_data_public->bWriteDefine = FALSE; + tpm_nv_data_public->dataSize = 0; + return; +} + +/* TPM_NVDataPublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVDataPublic_Init() + After use, call TPM_NVDataPublic_Delete() to free memory +*/ + +TPM_RESULT TPM_NVDataPublic_Load(TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataPublic_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_DATA_PUBLIC, stream, stream_size); + } + /* load nvIndex */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_data_public->nvIndex), stream, stream_size); + } + /* load pcrInfoRead */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoRead), stream, stream_size, optimize); + } + /* load pcrInfoWrite */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoWrite), stream, stream_size, optimize); + } + /* load permission */ + if (rc == 0) { + rc = TPM_NVAttributes_Load(&(tpm_nv_data_public->permission), stream, stream_size); + } + /* load bReadSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); + } + /* load bWriteSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); + } + /* load bWriteDefine */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteDefine), stream, stream_size); + } + /* load dataSize */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_data_public->dataSize), stream, stream_size); + } + return rc; +} + +/* TPM_NVDataPublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_NVDataPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataPublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_PUBLIC); + } + /* store nvIndex */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->nvIndex); + } + /* store pcrInfoRead */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoRead), optimize); + } + /* store pcrInfoWrite */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoWrite), optimize); + } + /* store permission */ + if (rc == 0) { + rc = TPM_NVAttributes_Store(sbuffer, &(tpm_nv_data_public->permission)); + } + /* store bReadSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteDefine */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteDefine), sizeof(TPM_BOOL)); + } + /* store dataSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->dataSize); + } + return rc; +} + +/* TPM_NVDataPublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_NVDataPublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVDataPublic_Delete(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) +{ + printf(" TPM_NVDataPublic_Delete:\n"); + if (tpm_nv_data_public != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoRead)); + TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoWrite)); + TPM_NVAttributes_Delete(&(tpm_nv_data_public->permission)); + TPM_NVDataPublic_Init(tpm_nv_data_public); + } + return; +} + +/* + TPM_NV_DATA_SENSITIVE +*/ + +/* TPM_NVDataSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVDataSensitive_Init(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + printf(" TPM_NVDataSensitive_Init:\n"); + TPM_NVDataPublic_Init(&(tpm_nv_data_sensitive->pubInfo)); + TPM_Secret_Init(tpm_nv_data_sensitive->authValue); + tpm_nv_data_sensitive->data = NULL; + TPM_Digest_Init(tpm_nv_data_sensitive->digest); + return; +} + +/* TPM_NVDataSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVDataSensitive_Init() + After use, call TPM_NVDataSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_NVDataSensitive_Load(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive, + TPM_TAG nvEntriesVersion, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_BOOL optimize; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_Load: nvEntriesVersion %04hx\n", nvEntriesVersion); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_DATA_SENSITIVE, stream, stream_size); + } + /* load pubInfo */ + if (rc == 0) { + /* versions after V1 optimise the serialization */ + optimize = (nvEntriesVersion != TPM_TAG_NVSTATE_NV_V1); + rc = TPM_NVDataPublic_Load(&(tpm_nv_data_sensitive->pubInfo), + stream, stream_size, + optimize); /* optimize digestAtRelease */ + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_nv_data_sensitive->authValue, stream, stream_size); + } + /* is the nvIndex GPIO space */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); + } + /* allocate memory for data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Malloc(&(tpm_nv_data_sensitive->data), + tpm_nv_data_sensitive->pubInfo.dataSize); + } + /* load data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Loadn(tpm_nv_data_sensitive->data, tpm_nv_data_sensitive->pubInfo.dataSize, + stream, stream_size); + } + /* create digest. The digest is not stored to save NVRAM space */ + if (rc == 0) { + rc = TPM_SHA1(tpm_nv_data_sensitive->digest, + sizeof(TPM_NV_INDEX), + (unsigned char *)&tpm_nv_data_sensitive->pubInfo.nvIndex, + TPM_AUTHDATA_SIZE, tpm_nv_data_sensitive->authValue, + 0, NULL); + } + return rc; +} + +/* TPM_NVDataSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + nvWrite TRUE indicates a write command, not a command to define the space. +*/ + +TPM_RESULT TPM_NVDataSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + TPM_RESULT rc = 0; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_SENSITIVE); + } + /* store pubInfo */ + if (rc == 0) { + rc = TPM_NVDataPublic_Store(sbuffer, &(tpm_nv_data_sensitive->pubInfo), + TRUE); /* optimize digestAtRelease */ + } + /* store authValue */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_nv_data_sensitive->authValue); + } + /* is the nvIndex GPIO space */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); + } + /* store data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_nv_data_sensitive->data, + tpm_nv_data_sensitive->pubInfo.dataSize); + } + return rc; +} + +/* TPM_NVDataSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_NVDataSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVDataSensitive_Delete(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + printf(" TPM_NVDataSensitive_Delete:\n"); + if (tpm_nv_data_sensitive != NULL) { + /* zero any secrets in NV index data */ + if (tpm_nv_data_sensitive->data != NULL) { + memset(tpm_nv_data_sensitive->data, 0xff, tpm_nv_data_sensitive->pubInfo.dataSize); + } + TPM_NVDataPublic_Delete(&(tpm_nv_data_sensitive->pubInfo)); + TPM_Secret_Delete(tpm_nv_data_sensitive->authValue); + free(tpm_nv_data_sensitive->data); + TPM_NVDataSensitive_Init(tpm_nv_data_sensitive); + } + return; +} + +/* TPM_NVDataSensitive_IsValidIndex() determines if 'nvIndex' is permissible for an NV defined space + TPM_NV_DATA_SENSITIVE structure. + + Some values have special meaning, so they are allowed for the TPM_NV_DefineSpace command but will + not actually define a space. +*/ + +TPM_RESULT TPM_NVDataSensitive_IsValidIndex(TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_IsValidIndex: nvIndex %08x\n", nvIndex); + if (rc == 0) { + if ((nvIndex == TPM_NV_INDEX_LOCK) || + (nvIndex == TPM_NV_INDEX0) || + (nvIndex == TPM_NV_INDEX_DIR)) { + printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal special index\n"); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + if ((nvIndex & TPM_NV_INDEX_RESVD) != 0) { + printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal reserved index\n"); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + rc = TPM_NVDataSensitive_IsValidPlatformIndex(nvIndex); + } + /* The GPIO range validity is platform dependent */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + return rc; +} + +/* TPM_NVDataSensitive_IsGPIO() determines if 'nvIndex' is in the GPIO range and is valid. + + Returns: + + TPM_SUCCESS , FALSE if 'nvIndex' is not in the GPIO range + TPM_SUCCESS , TRUE if 'nvIndex' is in the GPIO range and the platform allows GPIO defined space + TPM_BADINDEX, FALSE if 'nvIndex' is in the GPIO range and the platform does not allow GPIO + defined space +*/ + +TPM_RESULT TPM_NVDataSensitive_IsGPIO(TPM_BOOL *isGPIO, TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataSensitive_IsGPIO: nvIndex %08x\n", nvIndex); + *isGPIO = FALSE; +#if defined TPM_PCCLIENT + if (rc == 0) { + /* GPIO space allowed for PC Client */ + if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && + (nvIndex <= TPM_NV_INDEX_GPIO_END)) { + printf(" TPM_NVDataSensitive_IsGPIO: nvIndex is GPIO space\n"); + *isGPIO = TRUE; + } + } + /* #elif */ +#else + if (rc == 0) { + /* GPIO space cannot be defined in platforms with no GPIO */ + if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && + (nvIndex <= TPM_NV_INDEX_GPIO_END)) { + printf("TPM_NVDataSensitive_IsGPIO: Error, illegal index\n"); + rc = TPM_BADINDEX; + } + } +#endif + return rc; +} + +TPM_RESULT TPM_NVDataSensitive_IsValidPlatformIndex(TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataSensitive_IsValidPlatformIndex: nvIndex %08x\n", nvIndex); +#ifndef TPM_PCCLIENT + if (rc == 0) { + if (((nvIndex & TPM_NV_INDEX_PURVIEW_MASK) >> TPM_NV_INDEX_PURVIEW_BIT) == TPM_PC) { + printf(" TPM_NVDataSensitive_IsValidPlatformIndex: Error, PC Client index\n"); + rc = TPM_BADINDEX; + } + } +#endif + return rc; +} + +/* + NV Index Entries + + This handles the in-memory copy of NV defined space +*/ + +/* + TPM_NVIndexEntries_Init() initializes the TPM_NV_INDEX_ENTRIES array +*/ + +void TPM_NVIndexEntries_Init(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + printf(" TPM_NVIndexEntries_Init:\n"); + tpm_nv_index_entries->nvIndexCount = 0; + tpm_nv_index_entries->tpm_nvindex_entry = NULL; + return; +} + +/* + TPM_NVIndexEntries_Delete() iterates through the entire TPM_NV_INDEX_ENTRIES array, deleting any + used entries. + + It then frees and reinitializes the array. +*/ + + +void TPM_NVIndexEntries_Delete(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + size_t i; + + printf(" TPM_NVIndexEntries_Delete: Deleting from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* free the entries */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + TPM_NVDataSensitive_Delete(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + /* free the array */ + free(tpm_nv_index_entries->tpm_nvindex_entry); + TPM_NVIndexEntries_Init(tpm_nv_index_entries); + return; +} + +/* TPM_NVIndexEntries_Trace() traces the TPM_NV_INDEX_ENTRIES array. + + Edit and call as required for debugging. +*/ + +void TPM_NVIndexEntries_Trace(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + uint32_t i; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + + printf("\tTPM_NVIndexEntries_Trace: %u slots\n", tpm_nv_index_entries->nvIndexCount); + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf("\tTPM_NVIndexEntries_Trace: TPM_NV_DATA_SENSITIVE.data %p\n", + tpm_nv_data_sensitive->data); + } + return; +} + +/* + TPM_NVIndexEntries_Load() loads the TPM_NV_INDEX_ENTRIES array from a stream. + + The first data in the stream must be a uint32_t count of the number of entries to follow. +*/ + +TPM_RESULT TPM_NVIndexEntries_Load(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + TPM_TAG nvEntriesVersion; + + printf(" TPM_NVIndexEntries_Load:\n"); + /* get the NV entries version number */ + if (rc == 0) { + rc = TPM_Load16(&nvEntriesVersion, stream, stream_size); + } + /* check tag */ + if (rc == 0) { + switch (nvEntriesVersion) { + case TPM_TAG_NVSTATE_NV_V1: + case TPM_TAG_NVSTATE_NV_V2: + break; + default: + printf("TPM_NVIndexEntries_Load: Error (fatal), version %04x unsupported\n", + nvEntriesVersion); + rc = TPM_FAIL; + break; + } + } + /* nvIndexCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_index_entries->nvIndexCount), stream, stream_size); + } + /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ + if ((rc == 0) && (tpm_nv_index_entries->nvIndexCount > 0)) { + printf(" TPM_NVIndexEntries_Load: Loading %u slots\n", tpm_nv_index_entries->nvIndexCount); + rc = TPM_Malloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), + sizeof(TPM_NV_DATA_SENSITIVE) * tpm_nv_index_entries->nvIndexCount); + } + /* immediately after allocating, initialize so that _Delete is safe even on a _Load error */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + TPM_NVDataSensitive_Init(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + /* tpm_nvindex_entry array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + printf(" TPM_NVIndexEntries_Load: Loading slot %u\n", i); + if (rc == 0) { + rc = TPM_NVDataSensitive_Load(&(tpm_nv_index_entries->tpm_nvindex_entry[i]), + nvEntriesVersion, stream, stream_size); + } + /* should never load an unused entry */ + if (rc == 0) { + printf(" TPM_NVIndexEntries_Load: Loaded NV index %08x\n", + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { + printf("TPM_NVIndexEntries_Load: Error (fatal) Entry %u bad NV index %08x\n", + i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + rc = TPM_FAIL; + } + } + } + return rc; +} + +/* + TPM_NVIndexEntries_Store() serializes the TPM_NV_INDEX_ENTRIES array into a stream. Only used + entries are serialized. + + The first data in the stream is the used count, obtained by iterating through the array. +*/ + +TPM_RESULT TPM_NVIndexEntries_Store(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t count; /* number of used entries to store */ + size_t i; + + printf(" TPM_NVIndexEntries_Store: Storing from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* append the NV entries version number to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_NV_V2); + } + /* count the number of used entries */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&count, tpm_nv_index_entries); + } + /* store the actual used count, not the number of array entries */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, count); + } + /* tpm_nvindex_entry array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + printf(" TPM_NVIndexEntries_Store: Storing slot %lu NV index %08x\n", + (unsigned long)i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + rc = TPM_NVDataSensitive_Store(sbuffer, &(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + else { + printf(" TPM_NVIndexEntries_Store: Skipping unused slot %lu\n", (unsigned long)i); + } + } + return rc; +} + +/* TPM_NVIndexEntries_StClear() steps through each entry in the NV TPM_NV_INDEX_ENTRIES array, + setting the volatile flags to FALSE. +*/ + +void TPM_NVIndexEntries_StClear(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + size_t i; + + printf(" TPM_NVIndexEntries_StClear: Clearing %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at + TPM_Startup(ST_Clear) */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = FALSE; + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = FALSE; + } + return; +} + +/* TPM_NVIndexEntries_LoadVolatile() deserializes the stream into the volatile members of the + TPM_NV_INDEX_ENTRIES array. +*/ + +TPM_RESULT TPM_NVIndexEntries_LoadVolatile(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_NVIndexEntries_LoadVolatile:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1, stream, stream_size); + } + /* Get the number of used slots. This should be equal to the total number of slots. */ + if (rc == 0) { + rc = TPM_Load32(&usedCount, stream, stream_size); + } + if (rc == 0) { + printf(" TPM_NVIndexEntries_LoadVolatile: usedCount %u\n", usedCount); + if (usedCount != tpm_nv_index_entries->nvIndexCount) { + printf("TPM_NVIndexEntries_LoadVolatile: Error (fatal), " + "usedCount %u does not equal slot count %u\n", + usedCount, tpm_nv_index_entries->nvIndexCount); + rc = TPM_FAIL; + } + } + /* deserialize the stream into the TPM_NV_INDEX_ENTRIES array */ + for (entryIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; + entryIndex++) { + + tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); + printf(" TPM_NVIndexEntries_LoadVolatile: Loading index %08x\n", + tpm_nv_data_public->nvIndex); + /* load bReadSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); + } + /* load bWriteSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); + } + } + return rc; +} + +/* TPM_NVIndexEntries_StoreVolatile() serializes the volatile members of the + TPM_NV_INDEX_ENTRIES array into the TPM_STORE_BUFFER. +*/ + +TPM_RESULT TPM_NVIndexEntries_StoreVolatile(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_NVIndexEntries_StoreVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1); + } + /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be + some unused slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + /* store usedCount */ + if (rc == 0) { + printf(" TPM_NVIndexEntries_StoreVolatile: usedCount %u\n", usedCount); + rc = TPM_Sbuffer_Append32(sbuffer, usedCount); + } + /* save entries into the array */ + for (entryIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; + entryIndex++) { + /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, + unused slots will be reclaimed. */ + if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != + TPM_NV_INDEX_LOCK) { + + tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); + printf(" TPM_NVIndexEntries_StoreVolatile: Storing index %08x\n", + tpm_nv_data_public->nvIndex); + /* store bReadSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); + } + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetVolatile() saves an array of the NV defined space volatile flags. + + The array is used during a rollback, since the volatile flags are not stored in NVRAM +*/ + +TPM_RESULT TPM_NVIndexEntries_GetVolatile(TPM_NV_DATA_ST **tpm_nv_data_st, /* freed by caller */ + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + uint32_t usedIndex; + + printf(" TPM_NVIndexEntries_GetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be + some unused slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ + if ((rc == 0) && (usedCount > 0)) { + printf(" TPM_NVIndexEntries_GetVolatile: Aloocating for %u used slots\n", usedCount); + rc = TPM_Malloc((unsigned char **)tpm_nv_data_st, + sizeof(TPM_NV_DATA_ST) * usedCount); + } + /* save entries into the array */ + for (entryIndex = 0 , usedIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) && (usedCount > 0) ; + entryIndex++) { + /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, + unused slots will be reclaimed. */ + if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != + TPM_NV_INDEX_LOCK) { + + printf(" TPM_NVIndexEntries_GetVolatile: Saving slot %u at used %u NV index %08x\n", + entryIndex, usedIndex, + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex); + + printf(" TPM_NVIndexEntries_GetVolatile: bReadSTClear %u bWriteSTClear %u\n", + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear, + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear); + (*tpm_nv_data_st)[usedIndex].nvIndex = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex; + (*tpm_nv_data_st)[usedIndex].bReadSTClear = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear; + (*tpm_nv_data_st)[usedIndex].bWriteSTClear = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear; + usedIndex++; + } + } + return rc; +} + +/* TPM_NVIndexEntries_SetVolatile() restores an array of the NV defined space volatile flags. + + The array is used during a rollback, since the volatile flags are not stored in NVRAM +*/ + +TPM_RESULT TPM_NVIndexEntries_SetVolatile(TPM_NV_DATA_ST *tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t i; + + printf(" TPM_NVIndexEntries_SetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* Get the number of used slots. This should be equal to the total number of slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + if (rc == 0) { + if (usedCount != tpm_nv_index_entries->nvIndexCount) { + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "usedCount %u does not equal slot count %u\n", + usedCount, tpm_nv_index_entries->nvIndexCount); + rc = TPM_FAIL; + } + } + /* if the used count is non-zero, the volatile array should not be NULL */ + if (rc == 0) { + if ((usedCount > 0) && (tpm_nv_data_st == NULL)) { + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "usedCount %u unconsistant with volatile array NULL\n", usedCount); + rc = TPM_FAIL; + } + } + /* copy entries into the array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + printf(" TPM_NVIndexEntries_SetVolatile: slot %u index %08x\n", + i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + /* sanity check on a mismatch of entries between the save and restore */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != + tpm_nv_data_st[i].nvIndex) { + + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "mismatch NV entry %08x, saved %08x\n", + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex, + tpm_nv_data_st[i].nvIndex); + rc = TPM_FAIL; + } + /* restore entries from the array */ + else { + printf(" TPM_NVIndexEntries_SetVolatile: bReadSTClear %u bWriteSTClear %u\n", + tpm_nv_data_st[i].bReadSTClear, tpm_nv_data_st[i].bWriteSTClear); + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = + tpm_nv_data_st[i].bReadSTClear; + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = + tpm_nv_data_st[i].bWriteSTClear; + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetFreeEntry() gets a free entry in the TPM_NV_INDEX_ENTRIES array. + + If a free entry exists, it it returned. It should already be initialized. + + If a free entry does not exist, it it created and initialized. + + If a slot cannot be created, tpm_nv_data_sensitive returns NULL, so a subsequent free is safe. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetFreeEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + size_t i; + + printf(" TPM_NVIndexEntries_GetFreeEntry: Searching %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* for debug - trace the entire TPM_NV_INDEX_ENTRIES array */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf(" TPM_NVIndexEntries_GetFreeEntry: slot %lu entry %08x\n", + (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); + } + /* search the existing array for a free entry */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !done ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + /* if the entry is not used */ + if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { + printf(" TPM_NVIndexEntries_GetFreeEntry: Found free slot %lu\n", (unsigned long)i); + done = TRUE; + } + } + /* need to expand the array */ + if ((rc == 0) && !done) { + *tpm_nv_data_sensitive = NULL; + rc = TPM_Realloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), + sizeof(TPM_NV_DATA_SENSITIVE) * (i + 1)); + } + /* initialize the new entry in the array */ + if ((rc == 0) && !done) { + printf(" TPM_NVIndexEntries_GetFreeEntry: Created new slot at index %lu\n", + (unsigned long)i); + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + TPM_NVDataSensitive_Init(*tpm_nv_data_sensitive); + tpm_nv_index_entries->nvIndexCount++; + } + return rc; +} + +/* TPM_NVIndexEntries_GetEntry() gets the TPM_NV_DATA_SENSITIVE entry corresponding to nvIndex. + + Returns TPM_BADINDEX on non-existent nvIndex +*/ + +TPM_RESULT TPM_NVIndexEntries_GetEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_NVIndexEntries_GetEntry: Getting NV index %08x in %u slots\n", + nvIndex, tpm_nv_index_entries->nvIndexCount); + /* for debug tracing */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf(" TPM_NVIndexEntries_GetEntry: slot %lu entry %08x\n", + (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); + } + /* check for the special index that indicates an empty entry */ + if (rc == 0) { + if (nvIndex == TPM_NV_INDEX_LOCK) { + rc = TPM_BADINDEX; + } + } + for (i = 0 , found = FALSE ; + (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !found ; + i++) { + + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == nvIndex) { + printf(" TPM_NVIndexEntries_GetEntry: Found NV index at slot %lu\n", (unsigned long)i); + printf(" TPM_NVIndexEntries_GetEntry: permission %08x dataSize %u\n", + (*tpm_nv_data_sensitive)->pubInfo.permission.attributes, + (*tpm_nv_data_sensitive)->pubInfo.dataSize); + printf(" TPM_NVIndexEntries_GetEntry: " + "bReadSTClear %02x bWriteSTClear %02x bWriteDefine %02x\n", + (*tpm_nv_data_sensitive)->pubInfo.bReadSTClear, + (*tpm_nv_data_sensitive)->pubInfo.bWriteSTClear, + (*tpm_nv_data_sensitive)->pubInfo.bWriteDefine); + found = TRUE; + } + } + if (rc == 0) { + if (!found) { + printf(" TPM_NVIndexEntries_GetEntry: NV index not found\n"); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetUsedCount() returns the number of used entries in the TPM_NV_INDEX_ENTRIES + array. + + At startup, all entries will be used. If an NV index is deleted, the entryis marked unused, but + the TPM_NV_INDEX_ENTRIES space is not reclaimed until the next startup. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetUsedCount(uint32_t *count, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + size_t i; + + *count = 0; + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + (*count)++; + } + } + printf(" TPM_NVIndexEntries_GetUsedCount: Used count %d in %u slots\n", + *count, tpm_nv_index_entries->nvIndexCount); + return rc; +} + +/* TPM_NVIndexEntries_GetNVList() serializes a list of the used NV indexes into the + TPM_STORE_BUFFER +*/ + +TPM_RESULT TPM_NVIndexEntries_GetNVList(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_NVIndexEntries_GetNVList: Creating list from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + rc = TPM_Sbuffer_Append32(sbuffer, + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetUsedSpace() gets the NV space consumed by NV defined space indexes. + + It does it inefficiently but reliably by serializing the structure with the same function used + when writing to NV storage. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + + printf(" TPM_NVIndexEntries_GetUsedSpace:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize NV defined space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Store(&sbuffer, tpm_nv_index_entries); + } + /* get the serialized buffer and its length */ + if (rc == 0) { + TPM_Sbuffer_Get(&sbuffer, &buffer, usedSpace); + printf(" TPM_NVIndexEntries_GetUsedSpace: Used space %u\n", *usedSpace); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_NVIndexEntries_GetFreeSpace() gets the total free NV defined space. + + When defining an index, not all can be used for data, as some is consumed by metadata such as + authorization and the index number. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetFreeSpace(uint32_t *freeSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedSpace; + + printf(" TPM_NVIndexEntries_GetFreeSpace:\n"); + /* get the used space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedSpace(&usedSpace, tpm_nv_index_entries); + } + /* sanity check */ + if (rc == 0) { + if (usedSpace > TPM_MAX_NV_DEFINED_SIZE) { + printf("TPM_NVIndexEntries_GetFreeSpace: used %u greater than max %u\n", + usedSpace, TPM_MAX_NV_DEFINED_SIZE); + rc = TPM_NOSPACE; + } + } + /* calculate the free space */ + if (rc == 0) { + *freeSpace = TPM_MAX_NV_DEFINED_SIZE - usedSpace; + printf(" TPM_NVIndexEntries_GetFreeSpace: Free space %u\n", *freeSpace); + } + return rc; +} + +/* TPM_OwnerClear: rev 99 + 12. The TPM MUST deallocate all defined NV storage areas where + a. TPM_NV_PER_OWNERWRITE is TRUE if nvIndex does not have the "D" bit set + b. TPM_NV_PER_OWNERREAD is TRUE if nvIndex does not have the "D" bit set + c. The TPM MUST NOT deallocate any other currently defined NV storage areas. + + TPM_RevokeTrust: a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This + changes the TPM_OwnerClear handling of the same NV areas + + If deleteAllNvram is TRUE, all NVRAM is deleted. If it is FALSE, indexes with the D bit set are + not cleared. + + The write to NV space is done bu the caller. +*/ + +TPM_RESULT TPM_NVIndexEntries_DeleteOwnerAuthorized(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_BOOL deleteAllNvram) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* an entry in the array */ + + printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + /* get an entry in the array */ + tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + + /* if the index is in use */ + if (tpm_nv_data_sensitive->pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + /* if TPM_NV_PER_OWNERWRITE or TPM_NV_PER_OWNERREAD and nvIndex does not have the "D" + bit set */ + if ((tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE) || + (tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { + if (!(tpm_nv_data_sensitive->pubInfo.nvIndex & TPM_NV_INDEX_D_BIT) || + deleteAllNvram) { + /* delete the index */ + printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting NV index %08x\n", + tpm_nv_data_sensitive->pubInfo.nvIndex); + TPM_NVDataSensitive_Delete(tpm_nv_data_sensitive); + } + } + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetDataPublic() returns the TPM_NV_DATA_PUBLIC corresponding to the nvIndex + */ + +TPM_RESULT TPM_NVIndexEntries_GetDataPublic(TPM_NV_DATA_PUBLIC **tpm_nv_data_public, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + + printf(" TPM_NVIndexEntries_GetDataPublic: Getting data at NV index %08x\n", nvIndex); + if (rc == 0) { + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + tpm_nv_index_entries, + nvIndex); + } + if (rc == 0) { + *tpm_nv_data_public = &(tpm_nv_data_sensitive->pubInfo); + } + return rc; +} + +/* + Command Processing Functions +*/ + +/* 20.4 TPM_NV_ReadValue rev 114 + + Read a value from the NV store. This command uses optional owner authorization. + + Action 1 indicates that if the NV area is not locked then reading of the NV area continues + without ANY authorization. This is intentional, and allows a platform manufacturer to set the NV + areas, read them back, and then lock them all without having to install a TPM owner. +*/ + +TPM_RESULT TPM_Process_NVReadValue(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_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the area */ + uint32_t dataSize = 0; /* The size of the data area */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key: TPM Owner authorization */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL dir = FALSE; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO = FALSE; + BYTE *gpioData = NULL; + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER data; /* The data to set the area to */ + + printf("TPM_Process_NVReadValue: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get dataSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dataSize, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT | + TPM_CHECK_NV_NOAUTH)); + } + /* 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, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVReadValue: 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. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks are + ignored */ + /* a. Ignored checks include physical presence, owner authorization, PCR, bReadSTClear, + locality, TPM_NV_PER_OWNERREAD, disabled and deactivated */ + /* b. TPM_NV_PER_AUTHREAD is not ignored. */ + /* c. If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValue: index %08x offset %u dataSize %u\n", + nvIndex, offset, dataSize); + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVReadValue: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + } + /* 2. Set D1 a TPM_NV_DATA_AREA structure to the area pointed to by nvIndex, if not found + return TPM_BADINDEX */ + if (returnCode == TPM_SUCCESS) { + /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ + if (nvIndex == TPM_NV_INDEX_DIR) { + printf("TPM_Process_NVReadValue: Reading DIR\n"); + dir = TRUE; + } + else { + printf("TPM_Process_NVReadValue: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVReadValue: Error, NV index %08x not found\n", nvIndex); + } + } + } + /* Do not check permission for DIR, DIR is no-auth */ + if ((returnCode == TPM_SUCCESS) && !dir) { + /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ + if (tpm_state->tpm_permanent_flags.nvLocked) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERREAD is TRUE */ + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_Process_NVReadValue: Error, disabled\n"); + return TPM_DISABLED; + } + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ + else if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_Process_NVReadValue: Error, deactivated\n"); + return TPM_DEACTIVATED;; + } + } + /* NOTE: Intel software requires NV access disabled and deactivated */ + /* b. If D1 -> permission -> TPM_NV_PER_OWNERREAD is FALSE */ + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return + TPM_DEACTIVATED */ + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* NOTE: This is optional if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir) { + /* a. If D1 -> TPM_NV_PER_OWNERREAD is FALSE return TPM_AUTH_CONFLICT */ + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { + printf("TPM_Process_NVReadValue: Error, " + "owner authorization conflict, attributes %08x\n", + d1NvdataSensitive->pubInfo.permission.attributes); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. Validate command and parameters using TPM Owners authorization on error return + TPM_AUTHFAIL */ + 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_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !ignore_auth) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !dir) { + /* a. If D1 -> TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT */ + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD) { + printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_AUTHREAD\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. If D1 -> TPM_NV_PER_OWNERREAD is TRUE return TPM_AUTH_CONFLICT */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { + printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_OWNERREAD\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 6. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 7. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVReadValue: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + /* 8. If D1 -> TPM_NV_PER_READ_STCLEAR then */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && + /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ + (d1NvdataSensitive->pubInfo.bReadSTClear)) { + printf("TPM_Process_NVReadValue: Error, area locked by bReadSTClear\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 9. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ + /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on + mismatch */ + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS && !dir) { + /* 10. If dataSize is 0 then */ + if (dataSize == 0) { + printf("TPM_Process_NVReadValue: dataSize 0, setting bReadSTClear\n"); + /* a. Set D1 -> bReadSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; + /* b. Set data to NULL (output parameter dataSize to 0) */ + /* NOTE Done by TPM_SizedBuffer_Init */ + } + /* 11. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + dataSize; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + /* c. Set data to area pointed to by offset */ + if ((returnCode == TPM_SUCCESS) && !isGPIO) { + TPM_PrintFourLimit("TPM_Process_NVReadValue: read data", + d1NvdataSensitive->data + offset, dataSize); + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, d1NvdataSensitive->data + offset); + } + /* GPIO */ + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + printf("TPM_Process_NVReadValue: Reading GPIO\n"); + returnCode = TPM_IO_GPIO_Read(nvIndex, + dataSize, + gpioData, + tpm_state->tpm_number); + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, gpioData); + } + } + } + /* DIR read */ + if (returnCode == TPM_SUCCESS && dir) { + /* DIR is hard coded as a TPM_DIRVALUE array */ + if (returnCode == TPM_SUCCESS) { + s1Last = offset + dataSize; /* set to last data point */ + if (s1Last > TPM_DIGEST_SIZE) { + printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u too small\n", + TPM_DIGEST_SIZE); + returnCode = TPM_NOSPACE; + } + } + /* i.This includes partial reads of TPM_NV_INDEX_DIR. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValue: Copying data\n"); + returnCode = TPM_SizedBuffer_Set(&data, dataSize, + tpm_state->tpm_permanent_data.authDIR + offset); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVReadValue: 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 data */ + returnCode = TPM_SizedBuffer_Store(response, &data); + /* 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(&data); /* @1 */ + free(gpioData); /* @2 */ + return rcf; +} + +/* 20.5 TPM_NV_ReadValueAuth rev 87 + + This command requires that the read be authorized by a value set with the blob. +*/ + +TPM_RESULT TPM_Process_NVReadValueAuth(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_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset from the data area */ + uint32_t dataSize = 0; /* The size of the data area */ + TPM_AUTHHANDLE authHandle; /* The auth handle for the NV element authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA authHmac; /* HMAC key: nv element authorization */ + + /* 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_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + BYTE *gpioData = NULL; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER data; /* The data */ + + printf("TPM_Process_NVReadValueAuth: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get dataSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dataSize, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + authHmac, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVReadValueAuth: 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 + */ + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, on error return + TPM_BAD_INDEX */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValueAuth: index %08x offset %u dataSize %u\n", + nvIndex, offset, dataSize); + printf("TPM_Process_NVReadValueAuth: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVReadValueAuth: Error, NV index %08x not found\n", nvIndex); + } + } + /* 2. If D1 -> TPM_NV_PER_AUTHREAD is FALSE return TPM_AUTH_CONFLICT */ + if (returnCode == TPM_SUCCESS) { + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD)) { + printf("TPM_Process_NVReadValueAuth: Error, authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 3. Validate authHmac using D1 -> authValue on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_NV, + ordinal, + NULL, + &(d1NvdataSensitive->authValue), /* OIAP */ + d1NvdataSensitive->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + authHmac); /* Authorization digest for input */ + } + /* 4. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVReadValueAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + /* 5. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* 6. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ + /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on + mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS) { + /* 7. If D1 specifies TPM_NV_PER_READ_STCLEAR then */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && + /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ + (d1NvdataSensitive->pubInfo.bReadSTClear)) { + printf("TPM_Process_NVReadValueAuth: Error, area locked by bReadSTClear\n"); + returnCode = TPM_DISABLED_CMD; + } + } + if (returnCode == TPM_SUCCESS) { + /* 8. If dataSize is 0 then */ + if (dataSize == 0) { + printf("TPM_Process_NVReadValueAuth: dataSize 0, setting bReadSTClear\n"); + /* a. Set D1 -> bReadSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; + /* b. Set data to NULL */ + /* NOTE Done by TPM_SizedBuffer_Init */ + } + /* 9. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + dataSize; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVReadValueAuth: Error, NVRAM dataSize %u too small\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + /* c. Set data to area pointed to by offset */ + if ((returnCode == TPM_SUCCESS) && !isGPIO) { + TPM_PrintFourLimit("TPM_Process_NVReadValueAuth: read data", + d1NvdataSensitive->data + offset, dataSize); + returnCode = TPM_SizedBuffer_Set(&data, dataSize, d1NvdataSensitive->data + offset); + } + /* GPIO */ + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + printf("TPM_Process_NVReadValueAuth: Reading GPIO\n"); + returnCode = TPM_IO_GPIO_Read(nvIndex, + dataSize, + gpioData, + tpm_state->tpm_number); + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, gpioData); + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVReadValueAuth: 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 data */ + returnCode = TPM_SizedBuffer_Store(response, &data); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&data); /* @1 */ + return rcf; +} + +/* 20.2 TPM_NV_WriteValue rev 117 + + This command writes the value to a defined area. The write can be TPM Owner authorized or + unauthorized and protected by other attributes and will work when no TPM Owner is present. + + The action setting bGlobalLock to TRUE is intentionally before the action checking the + owner authorization. This allows code (e.g., a BIOS) to lock NVRAM without knowing the + owner authorization. + + The DIR (TPM_NV_INDEX_DIR) has the attributes TPM_NV_PER_OWNERWRITE and TPM_NV_WRITEALL. + + FIXME: A simpler way to do DIR might be to create the DIR as NV defined space at first + initialization and remove the special casing here. +*/ + +TPM_RESULT TPM_Process_NVWriteValue(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 */ + int irc; + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the NV Area */ + TPM_SIZED_BUFFER data; /* The data to set the area to */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner */ + TPM_NONCE nonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest HMAC key: TPM Owner auth */ + + /* 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 = NULL; + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL index0 = FALSE; + TPM_BOOL done = FALSE; + TPM_BOOL dir = FALSE; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive = NULL; + uint32_t s1Last; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO = FALSE; + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVWriteValue: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&data, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT | + TPM_CHECK_NV_NOAUTH)); + } + /* 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, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVWriteValue: 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 + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValue: index %08x offset %u dataSize %u\n", + nvIndex, offset, data.size); + TPM_PrintFourLimit("TPM_Process_NVWriteValue: data", data.buffer, data.size); + /* 1. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for + the max NV writes are ignored */ + /* a. Ignored checks include physical presence, owner authorization, TPM_NV_PER_OWNERWRITE, + PCR, bWriteDefine, bGlobalLock, bWriteSTClear, locality, disabled and deactivated */ + /* b. TPM_NV_PER_AUTHWRITE is not ignored. */ + /* a.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVWriteValue: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + if (nvIndex == TPM_NV_INDEX0) { + index0 = TRUE; + } + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + } + /* 2. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX + on error */ + if ((returnCode == TPM_SUCCESS) && !index0) { + /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ + if (nvIndex == TPM_NV_INDEX_DIR) { + printf("TPM_Process_NVWriteValue: Writing DIR\n"); + dir = TRUE; + } + else { + printf("TPM_Process_NVWriteValue: Loading data space from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVWriteValue: Error, NV index %08x not found\n", nvIndex); + } + } + } + if ((returnCode == TPM_SUCCESS) && !index0) { + /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ + if (tpm_state->tpm_permanent_flags.nvLocked) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE */ + if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ + (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_Process_NVWriteValue: Error, disabled\n"); + return TPM_DISABLED; + } + /* ii.If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ + else if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_Process_NVWriteValue: Error, deactivated\n"); + return TPM_DEACTIVATED;; + } + } + /* NOTE: Intel software requires NV access disabled and deactivated */ + /* b. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE */ + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return + TPM_DEACTIVATED */ + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir && !index0) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE return TPM_AUTH_CONFLICT */ + /* i. This check is ignored if nvIndex is TPM_NV_INDEX0. */ + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + printf("TPM_Process_NVWriteValue: Error, owner authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. Validate command and parameters using ownerAuth HMAC with TPM Owner authentication as the + secret, return TPM_AUTHFAIL on error */ + 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_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* NOTE: This is optional if ignore_auth is TRUE */ + 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, + ownerAuth); /* Authorization digest for input */ + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !index0) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE return TPM_AUTH_CONFLICT */ + if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ + (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + printf("TPM_Process_NVWriteValue: Error, no owner authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !index0) { + /* b. If no TPM Owner validate max NV writes without an owner */ + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_NVWriteValue: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + /* iv. Set NV1_INCREMENTED to TRUE */ + else { + nv1Incremented = TRUE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 6. If nvIndex = 0 then */ + if (nvIndex == 0) { + /* a. If dataSize is not 0, the TPM MAY return TPM_BADINDEX. */ + if (data.size != 0) { + printf("TPM_Process_NVWriteValue: Error, index 0 size %u\n", data.size); + returnCode = TPM_BADINDEX; + } + else { + /* b. Set TPM_STCLEAR_FLAGS -> bGlobalLock to TRUE */ + printf("TPM_Process_NVWriteValue: nvIndex 0, setting bGlobalLock\n"); + tpm_state->tpm_stclear_flags.bGlobalLock = TRUE; + /* c. Return TPM_SUCCESS */ + done = TRUE; + } + } + } + /* 7. If D1 -> permission -> TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT */ + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE) { + printf("TPM_Process_NVWriteValue: Error, authorization conflict, attributes %08x \n", + d1NvdataSensitive->pubInfo.permission.attributes); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 8. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 9. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVWriteValue: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 10. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && + /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteDefine)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bWriteDefine\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 11. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && + /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ + (tpm_state->tpm_stclear_flags.bGlobalLock)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bGlobalLock\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 12. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && + /* a. If D1 ->bWriteSTClear is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteSTClear)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + /* 13. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ + /* b. Compare P1 to D1 -> pcrInfoWrite -> digestAtRelease return TPM_WRONGPCRVAL on mismatch + */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + /* 14. If dataSize = 0 then */ + if (data.size == 0) { + printf("TPM_Process_NVWriteValue: dataSize 0, setting bWriteSTClear, bWriteDefine\n"); + /* a. Set D1 -> bWriteSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; + /* b. Set D1 -> bWriteDefine */ + if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if + FALSE */ + d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after structure is + written */ + writeAllNV = TRUE; + } + } + /* 15. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + data.size; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVWriteValue: Error, NVRAM dataSize %u too small\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. If D1 -> attributes specifies TPM_NV_PER_WRITEALL */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && + /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ + (data.size != d1NvdataSensitive->pubInfo.dataSize)) { + printf("TPM_Process_NVWriteValue: Error, Must write full %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + /* not GPIO */ + if (!isGPIO) { + /* wearout optimization, don't write if the data is the same */ + irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); + if (irc != 0) { + printf("TPM_Process_NVWriteValue: Copying data\n"); + /* d. Write the new value into the NV storage area */ + memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after + structure is written */ + writeAllNV = TRUE; + } + else { + printf("TPM_Process_NVWriteValue: Same data, no copy\n"); + } + } + /* GPIO */ + else { + printf("TPM_Process_NVWriteValue: Writing GPIO\n"); + returnCode = TPM_IO_GPIO_Write(nvIndex, + data.size, + data.buffer, + tpm_state->tpm_number); + } + } + } + } + /* DIR write */ + if ((returnCode == TPM_SUCCESS) && !done && dir) { + /* For TPM_NV_INDEX_DIR, the ordinal MUST NOT set an error code for the "if dataSize = 0" + action. However, the flags set in this case are not applicable to the DIR. */ + if (data.size != 0) { + /* DIR is hard coded as a TPM_DIRVALUE array, TPM_NV_WRITEALL is implied */ + if (returnCode == TPM_SUCCESS) { + if ((offset != 0) || (data.size != TPM_DIGEST_SIZE)) { + printf("TPM_Process_NVWriteValue: Error, Must write full DIR %u\n", + TPM_DIGEST_SIZE); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValue: Copying data\n"); + memcpy(tpm_state->tpm_permanent_data.authDIR, data.buffer, TPM_DIGEST_SIZE); + writeAllNV = TRUE; + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + /* 16. Set D1 -> bReadSTClear to FALSE (unlocked by a successful write) */ + d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; + } + /* 15.d Write the new value into the NV storage area */ + if (writeAllNV) { + printf("TPM_Process_NVWriteValue: Writing data to NVRAM\n"); + /* NOTE Don't do this step until just before the serialization */ + /* e. If NV1_INCREMENTED is TRUE */ + if (nv1Incremented) { + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVWriteValue: 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) && (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(&data); /* @1 */ + return rcf; +} + +/* 20.3 TPM_NV_WriteValueAuth rev 87 + + This command writes to a previously defined area. The area must require authorization to + write. This command is for using when authorization other than the owner authorization is to be + used. Otherwise, you should use TPM_NV_WriteValue +*/ + +TPM_RESULT TPM_Process_NVWriteValueAuth(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 */ + int irc; + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the chunk */ + TPM_SIZED_BUFFER data; /* The data to set the area to */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for NV element + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA authValue; /* HMAC key: NV element auth value */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVWriteValueAuth: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get data parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&data, &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(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + authValue, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVWriteValueAuth: 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 + */ + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX + on error */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValueAuth: index %08x offset %u dataSize %u\n", + nvIndex, offset, data.size); + TPM_PrintFourLimit("TPM_Process_NVWriteValueAuth: data", data.buffer, data.size); + printf("TPM_Process_NVWriteValueAuth: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVWriteValueAuth: Error, NV index %08x not found\n", nvIndex); + } + } + /* 2. If D1 -> attributes does not specify TPM_NV_PER_AUTHWRITE then return TPM_AUTH_CONFLICT */ + if (returnCode == TPM_SUCCESS) { + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE)) { + printf("TPM_Process_NVWriteValueAuth: Error, authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 3. Validate authValue using D1 -> authValue, return TPM_AUTHFAIL on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_NV, + ordinal, + NULL, + &(d1NvdataSensitive->authValue), /* OIAP */ + d1NvdataSensitive->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + authValue); /* Authorization digest for input */ + } + /* 4. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 5. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVWriteValueAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + /* 6. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ + /* b. Compare P1 to digestAtRelease return TPM_WRONGPCRVAL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS) { + /* 7. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && + /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteDefine)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteDefine\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 8. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && + /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ + (tpm_state->tpm_stclear_flags.bGlobalLock)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bGlobalLock\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 9. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && + /* a. If D1 -> bWriteSTClear is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteSTClear)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 10. If dataSize = 0 then */ + if (data.size == 0) { + printf("TPM_Process_NVWriteValueAuth: " + "dataSize 0, setting bWriteSTClear, bWriteDefine\n"); + /* a. Set D1 -> bWriteSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; + /* b. Set D1 -> bWriteDefine to TRUE */ + if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if + FALSE */ + d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after structure is + written */ + writeAllNV = TRUE; + } + } + /* 11. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + data.size; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVWriteValueAuth: Error, NVRAM dataSize %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. If D1 -> attributes specifies TPM_PER_WRITEALL */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && + /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ + (data.size != d1NvdataSensitive->pubInfo.dataSize)) { + printf("TPM_Process_NVWriteValueAuth: Error, Must write all %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + /* not GPIO */ + if (!isGPIO) { + /* wearout optimization, don't write if the data is the same */ + irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); + if (irc != 0) { + /* d. Write the new value into the NV storage area */ + printf("TPM_Process_NVWriteValueAuth: Copying data\n"); + memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after + structure is written */ + writeAllNV = TRUE; + } + else { + printf("TPM_Process_NVWriteValueAuth: Same data, no copy\n"); + } + } + /* GPIO */ + else { + printf("TPM_Process_NVWriteValueAuth: Writing GPIO\n"); + returnCode = TPM_IO_GPIO_Write(nvIndex, + data.size, + data.buffer, + tpm_state->tpm_number); + } + } + } + } + /* 12. Set D1 -> bReadSTClear to FALSE */ + if (returnCode == TPM_SUCCESS) { + d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; + printf("TPM_Process_NVWriteValueAuth: Writing data to NVRAM\n"); + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVWriteValueAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, 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(&data); /* @1 */ + return rcf; +} + +/* 20.1 TPM_NV_DefineSpace rev 109 + + This establishes the space necessary for the indicated index. The definition will include the + access requirements for writing and reading the area. + + Previously defined space at the index and new size is non-zero (and space is available, + etc.) -> redefine the index + + No previous space at the index and new size is non-zero (and space is available, etc.)-> + define the index + + Previously defined space at the index and new size is 0 -> delete the index + + No previous space at the index and new size is 0 -> error + + The space definition size does not include the area needed to manage the space. + + Setting TPM_PERMANENT_FLAGS -> nvLocked TRUE when it is already TRUE is not an error. + + For the case where pubInfo -> dataSize is 0, pubInfo -> pcrInfoRead and pubInfo -> pcrInfoWrite + are not used. However, since the general principle is to validate parameters before changing + state, the TPM SHOULD parse pubInfo completely before invalidating the data area. +*/ + +TPM_RESULT TPM_Process_NVDefineSpace(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_NV_INDEX newNVIndex = TPM_NV_INDEX_LOCK; /* from input TPM_NV_DATA_PUBLIC, initialize + to silence compiler */ + TPM_ENCAUTH encAuth; /* The encrypted AuthData, only valid if the attributes + require subsequent authorization */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for ownerAuth */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest HMAC key: ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* 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 = NULL; + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL done = FALSE; /* processing is done */ + TPM_DIGEST a1Auth; + TPM_NV_DATA_SENSITIVE *d1_old; /* possibly old data */ + TPM_NV_DATA_SENSITIVE *d1_new = NULL; /* new data */ + TPM_NV_DATA_PUBLIC *pubInfo = NULL; /* new, initialize to silence + compiler */ + uint32_t freeSpace; /* free space after allocating new + index */ + TPM_BOOL writeLocalities = FALSE; + TPM_BOOL physicalPresence; + TPM_BOOL foundOld = TRUE; /* index already exists, initialize + to silence compiler */ + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to silence + compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVDefineSpace: Ordinal Entry\n"); + /* This design gets a slot in the TPM_NV_INDEX_ENTRIES array, either an existing empty one or a + newly re'allocated one. The incoming parameters are deserialized directly into the slot. + + On success, the slot remains. On failure, the slot is deleted. There is no need to remove + the slot from the array. It can remain for the next call. + */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get or create a free index in the TPM_NV_INDEX_ENTRIES array */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_NVIndexEntries_GetFreeEntry(&d1_new, &(tpm_state->tpm_nv_index_entries)); + } + /* get pubInfo parameter */ + if (returnCode == TPM_SUCCESS) { + pubInfo = &(d1_new->pubInfo); /* pubInfo is an input parameter */ + returnCode = TPM_NVDataPublic_Load(pubInfo, + &command, ¶mSize, + FALSE); /* not optimized for digestAtRelease */ + /* The NV index cannot be immediately deserialized in the slot, or the function will think + that the index already exists. Therefore, the nvIndex parameter is saved and temporarily + set to empty until the old slot is deleted. */ + newNVIndex = pubInfo->nvIndex; /* save the possibly new index */ + pubInfo->nvIndex = TPM_NV_INDEX_LOCK; /* temporarily mark unused */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVDefineSpace: index %08x permission %08x dataSize %08x\n", + newNVIndex, pubInfo->permission.attributes, pubInfo->dataSize); + TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoRead", + pubInfo->pcrInfoRead.pcrSelection, + pubInfo->pcrInfoRead.digestAtRelease); + TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoWrite", + pubInfo->pcrInfoWrite.pcrSelection, + pubInfo->pcrInfoWrite.digestAtRelease); + /* get encAuth parameter */ + returnCode = TPM_Secret_Load(encAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER | TPM_CHECK_NV_NOAUTH); + } + /* 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, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVDefineSpace: 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. If pubInfo -> nvIndex == TPM_NV_INDEX_LOCK and tag = TPM_TAG_RQU_COMMAND */ + if ((returnCode == TPM_SUCCESS) && + (newNVIndex == TPM_NV_INDEX_LOCK) && + (tag == TPM_TAG_RQU_COMMAND)) { + /* a. If pubInfo -> dataSize is not 0, the command MAY return TPM_BADINDEX. */ + if (pubInfo->dataSize != 0) { + printf("TPM_Process_NVDefineSpace: Error, TPM_NV_INDEX_LOCK dataSize %u\n", + pubInfo->dataSize); + returnCode = TPM_BADINDEX; + } + else { + /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to TRUE */ + /* writeAllNV set to TRUE if nvLocked is being set, not if already set */ + printf("TPM_Process_NVDefineSpace: Setting nvLocked\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.nvLocked ), /* flag */ + TRUE); /* value */ + } + /* c. Return TPM_SUCCESS */ + done = TRUE; + } + /* 2. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for the + Max NV writes are ignored */ + /* a. Ignored checks include physical presence, owner authorization, 'D' bit check, bGlobalLock, + no authorization with a TPM owner present, bWriteSTClear, the check that pubInfo -> dataSize + is 0 in Action 5.c. (the no-authorization case), disabled and deactivated. */ + /* NOTE: The disabled and deactivated flags are conditionally checked by TPM_CheckState() using + the TPM_CHECK_NV_NOAUTH flag */ + /* ii. The check that pubInfo -> dataSize is 0 is still enforced in Action 6.f. (returning after + deleting a previously defined storage area) and Action 9.f. (not allowing a space of size 0 + to be defined). */ + /* i.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (returnCode == TPM_SUCCESS) { + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVDefineSpace: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + } + /* b.The check for pubInfo -> nvIndex == 0 in Action 3. is not ignored. */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (newNVIndex == TPM_NV_INDEX0) { + printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); + returnCode = TPM_BADINDEX; + } + } + /* 3. If pubInfo -> nvIndex has the D bit (bit 28) set to a 1 or pubInfo -> nvIndex == 0 then */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth) { + /* b. The D bit specifies an index value that is set in manufacturing and can never be + deleted or added to the TPM */ + if (newNVIndex & TPM_NV_INDEX_D_BIT) { + /* c. Index value of 0 is reserved and cannot be defined */ + /* a. Return TPM_BADINDEX */ + printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); + returnCode = TPM_BADINDEX; + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* b. authHandle session type MUST be OSAP */ + /* must get the HMAC key for the response even if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + /* a. The TPM MUST validate the command and parameters using the TPM Owner authentication and + ownerAuth, on error return TPM_AUTHFAIL */ + /* NOTE: This is optional if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* c. Create A1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 5. else (not auth1) */ + /* a. Validate the assertion of physical presence. Return TPM_BAD_PRESENCE on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVDefineSpace: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + /* b. If TPM Owner is present then return TPM_OWNER_SET. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_NVDefineSpace: Error, no authorization, but owner installed\n"); + returnCode = TPM_OWNER_SET; + } + } + /* c. If pubInfo -> dataSize is 0 then return TPM_BAD_DATASIZE. Setting the size to 0 represents + an attempt to delete the value without TPM Owner authentication. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Error, no owner authorization and dataSize 0\n"); + returnCode = TPM_BAD_DATASIZE; + } + } + /* d. Validate max NV writes without an owner */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_NVDefineSpace: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + else { + /* iv. Set NV1_INCREMENTED to TRUE */ + nv1Incremented = TRUE; + } + } + /* e. Set A1 to encAuth. There is no nonce or authorization to create the encryption string, + hence the AuthData value is passed in the clear */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { + TPM_Digest_Copy(a1Auth, encAuth); + } + /* 6. If pubInfo -> nvIndex points to a valid previously defined storage area then */ + /* 6.a. Map D1 a TPM_NV_DATA_SENSITIVE to the storage area */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Loading existing NV index %08x\n", newNVIndex); + returnCode = TPM_NVIndexEntries_GetEntry(&d1_old, + &(tpm_state->tpm_nv_index_entries), + newNVIndex); + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVDefineSpace: NV index %08x exists\n", newNVIndex); + foundOld = TRUE; + } + else if (returnCode == TPM_BADINDEX) { + returnCode = TPM_SUCCESS; /* non-existent index is not an error */ + foundOld = FALSE; + printf("TPM_Process_NVDefineSpace: Index %08x is new\n", newNVIndex); + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { + /* 6.b. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK then */ + if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) { + /* i. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE then return TPM_AREA_LOCKED */ + if (tpm_state->tpm_stclear_flags.bGlobalLock) { + printf("TPM_Process_NVDefineSpace: Error, index %08x (bGlobalLock) locked\n", + newNVIndex); + returnCode = TPM_AREA_LOCKED; + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { + /* 6.c. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) { + /* i. If D1 -> pubInfo -> bWriteSTClear is TRUE then return TPM_AREA_LOCKED */ + if (d1_old->pubInfo.bWriteSTClear) { + printf("TPM_Process_NVDefineSpace: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + } + /* NOTE Changed the Action order. Must terminate auth sessions while the old index digest + still exists. + */ + /* 6.f. The TPM invalidates authorization sessions */ + /* i. MUST invalidate all authorization sessions associated with D1 */ + /* ii. MAY invalidate any other authorization session */ + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_NV, + &(d1_old->digest)); + } + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + /* 6.d. Invalidate the data area currently pointed to by D1 and ensure that if the area is + reallocated no residual information is left */ + printf("TPM_Process_NVDefineSpace: Deleting index %08x\n", newNVIndex); + TPM_NVDataSensitive_Delete(d1_old); + /* must write deleted space back to NVRAM */ + writeAllNV = TRUE; + /* 6.e. If NV1_INCREMENTED is TRUE */ + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + /* NOTE Don't do this step until just before the serialization */ + } + /* g. If pubInfo -> dataSize is 0 then return TPM_SUCCESS */ + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Size 0, done\n"); + done = TRUE; + } + } + /* 7. Parse pubInfo -> pcrInfoRead */ + /* a. Validate pcrInfoRead structure on error return TPM_INVALID_STRUCTURE */ + /* i. Validation includes proper PCR selections and locality selections */ + /* NOTE: Done by TPM_NVDataPublic_Load() */ + /* 8. Parse pubInfo -> pcrInfoWrite */ + /* a. Validate pcrInfoWrite structure on error return TPM_INVALID_STRUCTURE */ + /* i. Validation includes proper PCR selections and locality selections */ + /* NOTE: Done by TPM_NVDataPublic_Load() */ + if ((returnCode == TPM_SUCCESS) && !done) { + /* b. If pcrInfoWrite -> localityAtRelease disallows some localities */ + if (pubInfo->pcrInfoRead.localityAtRelease != TPM_LOC_ALL) { + /* i. Set writeLocalities to TRUE */ + writeLocalities = TRUE; + } + /* c. Else */ + else { + /* i. Set writeLocalities to FALSE */ + writeLocalities = FALSE; + } + } + /* 9. Validate that the attributes are consistent */ + /* a. The TPM SHALL ignore the bReadSTClear, bWriteSTClear and bWriteDefine attributes during + the execution of this command */ + /* b. If TPM_NV_PER_OWNERWRITE is TRUE and TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT + */ + if ((returnCode == TPM_SUCCESS) && !done) { + if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && + (pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE)) { + printf("TPM_Process_NVDefineSpace: Error, write authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* c. If TPM_NV_PER_OWNERREAD is TRUE and TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT + */ + if ((returnCode == TPM_SUCCESS) && !done) { + if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERREAD) && + (pubInfo->permission.attributes & TPM_NV_PER_AUTHREAD)) { + printf("TPM_Process_NVDefineSpace: Error, read authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* d. If TPM_NV_PER_OWNERWRITE and TPM_NV_PER_AUTHWRITE and TPM_NV_PER_WRITEDEFINE and + TPM_NV_PER_PPWRITE and writeLocalities are all FALSE */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (!(pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && + !(pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE) && + !(pubInfo->permission.attributes & TPM_NV_PER_WRITEDEFINE) && + !(pubInfo->permission.attributes & TPM_NV_PER_PPWRITE) && + !writeLocalities) { + /* i. Return TPM_PER_NOWRITE */ + printf("TPM_Process_NVDefineSpace: Error, no write\n"); + returnCode = TPM_PER_NOWRITE; + } + } + /* e. Validate pubInfo -> nvIndex */ + /* i. Make sure that the index is applicable for this TPM return TPM_BADINDEX on error */ + if ((returnCode == TPM_SUCCESS) && !done) { + returnCode = TPM_NVDataSensitive_IsValidIndex(newNVIndex); + } + /* f. If dataSize is 0 return TPM_BAD_PARAM_SIZE */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Error, New index data size is zero\n"); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* 10. Create D1 a TPM_NV_DATA_SENSITIVE structure */ + /* NOTE Created and initialized d1_new directly in the TPM_NV_INDEX_ENTRIES array */ + /* a. Set D1 -> pubInfo to pubInfo */ + /* NOTE deserialized in place */ + if ((returnCode == TPM_SUCCESS) && !done) { + /* b. Set D1 -> authValue to A1 */ + TPM_Digest_Copy(d1_new->authValue, a1Auth); + /* c. Set D1 -> pubInfo -> bReadSTClear to FALSE */ + /* d. Set D1 -> pubInfo -> bWriteSTClear to FALSE */ + /* e. Set D1 -> pubInfo -> bWriteDefine to FALSE */ + pubInfo->bReadSTClear = FALSE; + pubInfo->bWriteSTClear = FALSE; + pubInfo->bWriteDefine = FALSE; + } + if ((returnCode == TPM_SUCCESS) && !done) { + /* assign the empty slot to the index now so it will be counted as used space during the + serialization. */ + pubInfo->nvIndex = newNVIndex; + /* 12.a. Reserve NV space for pubInfo -> dataSize + + NOTE: Action is out or order. Must allocate data space now so that the serialization + inherent in TPM_NVIndexEntries_GetFreeSpace() is valid + */ + returnCode = TPM_Malloc(&(d1_new->data), pubInfo->dataSize); + } + /* 11. Validate that sufficient NV is available to store D1 and pubInfo -> dataSize bytes of + data*/ + /* a. return TPM_NOSPACE if pubInfo -> dataSize is not available in the TPM */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Allocated %u data bytes at %p\n", + pubInfo->dataSize, d1_new->data); + printf("TPM_Process_NVDefineSpace: Checking for %u bytes free space\n", pubInfo->dataSize); + returnCode = TPM_NVIndexEntries_GetFreeSpace(&freeSpace, + &(tpm_state->tpm_nv_index_entries)); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_NVDefineSpace: Error: No space\n"); + } + } + /* if there is no free space, free the NV index in-memory structure. This implicitly removes + the entry from tpm_nv_index_entries. If pubInfo -> nvIndex is TPM_NV_INDEX_TRIAL, the entry + should also be removed. */ + if ((returnCode != TPM_SUCCESS) || + (newNVIndex == TPM_NV_INDEX_TRIAL)) { + if (newNVIndex == TPM_NV_INDEX_TRIAL) { + printf("TPM_Process_NVDefineSpace: nvIndex is TPM_NV_INDEX_TRIAL, done\n"); + /* don't actually write, just return success or failure */ + done = TRUE; + } + TPM_NVDataSensitive_Delete(d1_new); + } + /* 12. If pubInfo -> nvIndex is not TPM_NV_INDEX_TRIAL */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Creating index %08x\n", newNVIndex); + /* b. Set all bytes in the newly defined area to 0xFF */ + memset(d1_new->data, 0xff, pubInfo->dataSize); + /* must write newly defined space back to NVRAM */ + writeAllNV = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* c. If NV1_INCREMENTED is TRUE */ + if (nv1Incremented) { + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + /* 13. Ignore continueAuthSession on input and set to FALSE on output */ + continueAuthSession = FALSE; + } + /* write the file to NVRAM */ + /* write back TPM_PERMANENT_DATA and TPM_PERMANENT_FLAGS if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVDefineSpace: 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) && (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 + */ + return rcf; +} + +/* 27.3 DIR commands rev 87 + + The DIR commands are replaced by the NV storage commands. + + The DIR [0] in 1.1 is now TPM_PERMANENT_DATA -> authDIR[0] and is always available for the TPM to + use. It is accessed by DIR commands using dirIndex 0 and by NV commands using nvIndex + TPM_NV_INDEX_DIR. + + If the TPM vendor supports additional DIR registers, the TPM vendor may return errors or provide + vendor specific mappings for those DIR registers to NV storage locations. + + 1. A dirIndex value of 0 MUST corresponds to an NV storage nvIndex value TPM_NV_INDEX_DIR. + + 2. The TPM vendor MAY return errors or MAY provide vendor specific mappings for DIR dirIndex + values greater than 0 to NV storage locations. +*/ + +/* 27.3.1 TPM_DirWriteAuth rev 87 + + The TPM_DirWriteAuth operation provides write access to the Data Integrity Registers. DIRs are + non-volatile memory registers held in a TPM-shielded location. Owner authentication is required + to authorize this action. + + Access is also provided through the NV commands with nvIndex TPM_NV_INDEX_DIR. Owner + authorization is not required when nvLocked is FALSE. + + Version 1.2 requires only one DIR. If the DIR named does not exist, the TPM_DirWriteAuth + operation returns TPM_BADINDEX. +*/ + +TPM_RESULT TPM_Process_DirWriteAuth(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_DIRINDEX dirIndex; /* Index of the DIR */ + TPM_DIRVALUE newContents; /* New value to be stored in named DIR */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for command. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs. HMAC key: + ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DirWriteAuth: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dirIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); + } + /* get newContents parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirWriteAuth: dirIndex %08x\n", dirIndex); + returnCode = TPM_Digest_Load(newContents, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DirWriteAuth: newContents", newContents); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DirWriteAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that authHandle contains a TPM Owner AuthData to execute the TPM_DirWriteAuth + command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that dirIndex points to a valid DIR on this TPM */ + if (returnCode == TPM_SUCCESS) { + if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ + printf("TPM_Process_DirWriteAuth: Error, Invalid index %08x\n", dirIndex); + returnCode = TPM_BADINDEX; + } + } + /* 3. Write newContents into the DIR pointed to by dirIndex */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirWriteAuth: Writing data\n"); + TPM_Digest_Copy(tpm_state->tpm_permanent_data.authDIR, newContents); + /* write back TPM_PERMANENT_DATA */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DirWriteAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 27.3.2 TPM_DirRead rev 87 + + The TPM_DirRead operation provides read access to the DIRs. No authentication is required to + perform this action because typically no cryptographically useful AuthData is available early in + boot. TSS implementors may choose to provide other means of authorizing this action. Version 1.2 + requires only one DIR. If the DIR named does not exist, the TPM_DirRead operation returns + TPM_BADINDEX. +*/ + +TPM_RESULT TPM_Process_DirRead(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_DIRINDEX dirIndex; /* Index of the DIR to be read */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DirRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dirIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirRead: dirIndex %08x\n", dirIndex); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DirRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that dirIndex points to a valid DIR on this TPM */ + if (returnCode == TPM_SUCCESS) { + if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ + printf("TPM_Process_DirRead: Error, Invalid index %08x\n", dirIndex); + returnCode = TPM_BADINDEX; + } + } + /* 2. Return the contents of the DIR in dirContents */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirRead: Reading data\n"); + TPM_PrintFour("TPM_Process_DirRead:", tpm_state->tpm_permanent_data.authDIR); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DirRead: 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; + /* append dirContents */ + returnCode = TPM_Digest_Store(response, tpm_state->tpm_permanent_data.authDIR); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm12/tpm_nvram.h b/src/tpm12/tpm_nvram.h new file mode 100644 index 0000000..4bea9ef --- /dev/null +++ b/src/tpm12/tpm_nvram.h @@ -0,0 +1,201 @@ +/********************************************************************************/ +/* */ +/* NVRAM Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram.h 4528 2011-03-29 22:16:28Z 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. */ +/********************************************************************************/ + +#ifndef TPM_NVRAM_H +#define TPM_NVRAM_H + +#include <sys/types.h> + +#include "tpm_global.h" +#include "tpm_types.h" + +/* + NVRAM common functions +*/ + +/* + TPM_NV_ATTRIBUTES +*/ + +void TPM_NVAttributes_Init(TPM_NV_ATTRIBUTES *tpm_nv_attributes); +TPM_RESULT TPM_NVAttributes_Load(TPM_NV_ATTRIBUTES *tpm_nv_attributes, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVAttributes_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_ATTRIBUTES *tpm_nv_attributes); +void TPM_NVAttributes_Delete(TPM_NV_ATTRIBUTES *tpm_nv_attributes); + +void TPM_NVAttributes_Copy(TPM_NV_ATTRIBUTES *tpm_nv_attributes_dest, + TPM_NV_ATTRIBUTES *tpm_nv_attributes_src); + +/* + TPM_NV_DATA_PUBLIC +*/ + +void TPM_NVDataPublic_Init(TPM_NV_DATA_PUBLIC *tpm_nv_data_public); +TPM_RESULT TPM_NVDataPublic_Load(TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize); +TPM_RESULT TPM_NVDataPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + TPM_BOOL optimize); +void TPM_NVDataPublic_Delete(TPM_NV_DATA_PUBLIC *tpm_nv_data_public); + +/* + TPM_NV_DATA_SENSITIVE +*/ + +void TPM_NVDataSensitive_Init(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); +TPM_RESULT TPM_NVDataSensitive_Load(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive, + TPM_TAG nvEntriesVersion, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVDataSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); +void TPM_NVDataSensitive_Delete(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); + +TPM_RESULT TPM_NVDataSensitive_IsValidIndex(TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVDataSensitive_IsGPIO(TPM_BOOL *isGPIO, TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVDataSensitive_IsValidPlatformIndex(TPM_NV_INDEX nvIndex); + +/* + NV Index Entries +*/ + +void TPM_NVIndexEntries_Init(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_Delete(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_Trace(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_Load(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVIndexEntries_Store(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_StClear(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_LoadVolatile(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVIndexEntries_StoreVolatile(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetVolatile(TPM_NV_DATA_ST **tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_SetVolatile(TPM_NV_DATA_ST *tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetFreeEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVIndexEntries_GetUsedCount(uint32_t *count, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetNVList(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_DeleteOwnerAuthorized(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_BOOL deleteAllNvram); +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetFreeSpace(uint32_t *freeSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetDataPublic(TPM_NV_DATA_PUBLIC **tpm_nv_data_public, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex); + +/* + Processing Functions +*/ + + +TPM_RESULT TPM_Process_NVReadValue(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 TPM_Process_NVReadValueAuth(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 TPM_Process_NVWriteValue(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 TPM_Process_NVWriteValueAuth(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 TPM_Process_NVDefineSpace(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 TPM_Process_DirRead(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 TPM_Process_DirWriteAuth(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); + +#endif diff --git a/src/tpm12/tpm_nvram_const.h b/src/tpm12/tpm_nvram_const.h new file mode 100644 index 0000000..68ee97c --- /dev/null +++ b/src/tpm12/tpm_nvram_const.h @@ -0,0 +1,138 @@ +/********************************************************************************/ +/* */ +/* NVRAM Constants */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram_const.h 4528 2011-03-29 22:16:28Z 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. */ +/********************************************************************************/ + +#ifndef TPM_NVRAM_CONST_H +#define TPM_NVRAM_CONST_H + +/* + These are implementation specific constants +*/ + +/* + TPMS_MAX defines the maximum number of TPM instances. +*/ + +#define TPMS_MAX 1 + +/* + NVRAM storage directory path +*/ + + +#ifdef TPM_NV_DISK +/* TPM_NV_DISK uses the TPM_PATH environment variable */ +#endif + +/* Defines the maximum size of the NV defined space, the NV indexes created by TPM_NV_DefineSpace. + + The PC Client requires 2048 bytes. There is at least (currently) 6 bytes of overhead, a tag and + a count. +*/ + +#ifndef TPM_MAX_NV_DEFINED_SIZE +#define TPM_MAX_NV_DEFINED_SIZE 2100 +#endif + +/* TPM_MAX_NV_SPACE defines the maximum NV space for non-volatile state. + + It does not include the area used for TPM_SaveState. + + See TPM_OWNER_EVICT_KEY_HANDLES, TPM_MIN_COUNTERS, TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, etc. and the platform specific requirements for NV defined + space. +*/ + +#ifndef TPM_MAX_NV_SPACE + + + +#ifdef TPM_NV_DISK +#define TPM_MAX_NV_SPACE 100000 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_NV_SPACE */ + +#ifndef TPM_MAX_NV_SPACE +#error "TPM_MAX_NV_SPACE is not defined" +#endif + +/* TPM_MAX_SAVESTATE_SPACE defines the maximum NV space for TPM saved state. + + It is used by TPM_SaveState + + NOTE This macro is based on the maximum number of loaded keys and session. For example, 3 loaded + keys, 3 OSAP sessions, and 1 transport session consumes about 2500 bytes. + + See TPM_KEY_HANDLES, TPM_NUM_PCR, TPM_MIN_AUTH_SESSIONS, TPM_MIN_TRANS_SESSIONS, + TPM_MIN_DAA_SESSIONS, TPM_MIN_SESSION_LIST, etc. +*/ + +#ifndef TPM_MAX_SAVESTATE_SPACE + + + +#ifdef TPM_NV_DISK +#define TPM_MAX_SAVESTATE_SPACE 100000 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_SAVESTATE_SPACE */ + +#ifndef TPM_MAX_SAVESTATE_SPACE +#error "TPM_MAX_SAVESTATE_SPACE is not defined" +#endif + +/* TPM_MAX_VOLATILESTATE_SPACE defines the maximum NV space for TPM volatile state. + + It is used for applications that save and restore the entire TPM volatile is a non-standard way. +*/ + +#ifndef TPM_MAX_VOLATILESTATE_SPACE + + +#ifdef TPM_NV_DISK +#define TPM_MAX_VOLATILESTATE_SPACE 524288 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_VOLATILESTATE_SPACE */ + +#ifndef TPM_MAX_VOLATILESTATE_SPACE +#error "TPM_MAX_VOLATILESTATE_SPACE is not defined" +#endif + +#endif diff --git a/src/tpm12/tpm_openssl_helpers.c b/src/tpm12/tpm_openssl_helpers.c new file mode 100644 index 0000000..c798acb --- /dev/null +++ b/src/tpm12/tpm_openssl_helpers.c @@ -0,0 +1,135 @@ +/********************************************************************************/ +/* */ +/* OpenSSL helper functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* (c) Copyright IBM Corporation 2020. */ +/* */ +/* 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 <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/bn.h> + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_openssl_helpers.h" + +#include "tpm_crypto.h" + +#if USE_OPENSSL_FUNCTIONS_RSA + +TPM_RESULT TPM_RSAGenerateEVP_PKEY(EVP_PKEY **pkey, /* out: pkey */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM * n = NULL; + BIGNUM * e = NULL; + BIGNUM * d = NULL; + RSA * rsakey = NULL; + + /* sanity check for the free */ + if (rc == 0) { + if (*pkey != NULL) { + printf("TPM_RSAGeneratePrivateToken: Error (fatal), pkey %p should be NULL\n", + *pkey); + rc = TPM_FAIL; + } + } + /* construct the OpenSSL private key object */ + if (rc == 0) { + *pkey = EVP_PKEY_new(); /* freed by caller */ + if (*pkey == NULL) { + printf("TPM_RSAGeneratePrivateToken: Error in EVP_PKEY_new()\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed by caller */ + } + if (rc == 0) { + if (darr != NULL) { + rc = TPM_bin2bn((TPM_BIGNUM *)&d, darr, dbytes); /* freed by caller */ + } + } + if (rc == 0) { + rsakey = RSA_new(); + if (rsakey == NULL) { + printf("TPM_RSAGeneratePrivateToken: Error in RSA_new()\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = RSA_set0_key(rsakey, n, e, d); + if (irc != 1) { + printf("TPM_RSAGeneratePrivateToken: Error in RSA_set0_key()\n"); + rc = TPM_FAIL; + } else { + n = NULL; + e = NULL; + d = NULL; + } + } + if (rc == 0) { + RSA_set_flags(rsakey, RSA_FLAG_NO_BLINDING); + irc = EVP_PKEY_assign_RSA(*pkey, rsakey); + if (irc == 0) { + printf("TPM_RSAGeneratePrivateToken: Error in EVP_PKEY_assign_RSA()\n"); + rc = TPM_FAIL; + } else { + rsakey = NULL; + } + } + + if (rc != 0) { + EVP_PKEY_free(*pkey); + *pkey = NULL; + RSA_free(rsakey); + BN_free(n); + BN_free(e); + BN_clear_free(d); + } + + return rc; +} + +#endif + diff --git a/src/tpm12/tpm_openssl_helpers.h b/src/tpm12/tpm_openssl_helpers.h new file mode 100644 index 0000000..330fd98 --- /dev/null +++ b/src/tpm12/tpm_openssl_helpers.h @@ -0,0 +1,50 @@ +/********************************************************************************/ +/* */ +/* OpenSSL helper functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* (c) Copyright IBM Corporation 2020. */ +/* */ +/* 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. */ +/********************************************************************************/ + +#ifndef TPM_OPENSSL_HELPERS_H +#define TPM_OPENSSL_HELPERS_H + +TPM_RESULT TPM_RSAGenerateEVP_PKEY(EVP_PKEY **pkey, /* out: pkey */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes); + +#endif diff --git a/src/tpm12/tpm_owner.c b/src/tpm12/tpm_owner.c new file mode 100644 index 0000000..4360505 --- /dev/null +++ b/src/tpm12/tpm_owner.c @@ -0,0 +1,1968 @@ +/********************************************************************************/ +/* */ +/* Ownership Processing */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_owner.c 4620 2011-09-07 21:43:19Z 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 <stdlib.h> + +#include "tpm_audit.h" +#include "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_session.h" +#include "tpm_sizedbuffer.h" +#include "tpm_transport.h" + +#include "tpm_owner.h" + +/* Flags involved with clearing an owner: + + pFlags.disableOwnerClear + set by TPM_DisableOwnerClear + clear by successful owner clear + vFlags.disableForceClear + set by TPM_DisableForceClear + clear by TPM_Init + + TPM_OwnerClear + requires ownerAuth + pFlags.disableOwnerClear == FALSE + TPM_ForceClear + requires physical presence + vFlags.disableForceClear == FALSE +*/ + +/* 6.1 TPM_TakeOwnership rev 114 + + This command inserts the TPM Ownership value into the TPM. +*/ + +TPM_RESULT TPM_Process_TakeOwnership(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* bytes left in command */ + 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 ownership protocol in use */ + TPM_SIZED_BUFFER encOwnerAuth; /* The owner authorization data encrypted with PUBEK */ + TPM_SIZED_BUFFER encSrkAuth; /* The SRK authorization data encrypted with PUBEK */ + TPM_KEY srkParams; /* Structure containing all parameters of new SRK. + pubKey.keyLength & encSize are both 0. This structure + MAY be TPM_KEY12. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for this command */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization handle */ + TPM_AUTHDATA ownerAuth; /* Authorization digest for input params. HMAC key: the new + ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET a1Auth; /* decrypt of encOwnerAuth */ + uint32_t a1Auth_length; /* length of decrypted A1 */ + TPM_SECRET a2SrkAuth; /* decrypt of encSrkAuth */ + uint32_t a2SrkAuth_length; /* length of decrypted A2 */ + TPM_RSA_KEY_PARMS *srkRSAKeyParms; + TPM_STORE_ASYMKEY *srkStoreAsymkey; + TPM_STORE_BUFFER asymKeySbuffer; /* serialized SRK asymkey */ + TPM_KEY *srk; /* pointer to SRK in permanent data */ + TPM_SIZED_BUFFER exponent; /* default exponent */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back NV */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + int ver; /* TPM_KEY or TPM_KEY12 */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY srkPub; /* Structure containing all parameters of new SRK, + srkPub.encData is set to 0. */ + + printf("TPM_Process_TakeOwnership: Ordinal Entry\n"); + srk = &(tpm_state->tpm_permanent_data.srk); /* get pointer to SRK in permanent data */ + + /* so that Delete's are safe */ + TPM_SizedBuffer_Init(&encOwnerAuth); /* freed @1 */ + TPM_SizedBuffer_Init(&encSrkAuth); /* freed @2 */ + TPM_Key_Init(&srkParams); /* freed @3 */ + TPM_Key_Init(&srkPub); /* freed @5 */ + TPM_SizedBuffer_Init(&exponent); /* freed @6 */ + TPM_Sbuffer_Init(&asymKeySbuffer); /* freed @7 */ + /* + 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 encOwnerAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: protocolID %04hx\n", protocolID); + returnCode = TPM_SizedBuffer_Load(&encOwnerAuth, &command, ¶mSize); + } + /* get encSrkAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encSrkAuth, &command, ¶mSize); + } + /* get srkParams parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&srkParams, &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_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TakeOwnership: 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. If TPM_PERMANENT_DATA -> ownerAuth is valid return TPM_OWNER_SET */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Checking TPM state\n"); + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_TakeOwnership: Error, owner already installed\n"); + returnCode = TPM_OWNER_SET; + } + } + /* 2. If TPM_PERMANENT_FLAGS -> ownership is FALSE return TPM_INSTALL_DISABLED */ + if (returnCode == TPM_SUCCESS) { + if (!(tpm_state->tpm_permanent_flags.ownership)) { + printf("TPM_Process_TakeOwnership: Error, ownership is false\n"); + returnCode = TPM_INSTALL_DISABLED; + } + } + /* 3. If TPM_PERMANENT_DATA -> endorsementKey is invalid return TPM_NO_ENDORSEMENT */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == TPM_KEY_UNINITIALIZED) { + printf("TPM_Process_TakeOwnership: Error, endorsement key is invalid\n"); + returnCode = TPM_NO_ENDORSEMENT; + } + } + /* 4. Verify that authHandle is of type OIAP on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OIAP, + 0, /* OSAP entity type */ + ordinal, + NULL, + NULL, /* no OIAP authorization */ + NULL); + } + /* 5. If protocolID is not TPM_PID_OWNER, the TPM MAY return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (protocolID != TPM_PID_OWNER) { + printf("TPM_Process_TakeOwnership: Error, bad protocolID\n"); + returnCode = TPM_BAD_PARAMETER; + + } + } + /* 6. Create A1 a TPM_SECRET by decrypting encOwnerAuth using PRIVEK as the key */ + /* a. This requires that A1 was encrypted using the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptH(a1Auth, /* decrypted data */ + &a1Auth_length, /* actual size of A1 */ + TPM_SECRET_SIZE, /* size of A1 buffer */ + encOwnerAuth.buffer, /* encrypted data */ + encOwnerAuth.size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* b. Validate that A1 is a length of 20 bytes, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (a1Auth_length != TPM_SECRET_SIZE) { + printf("TPM_Process_TakeOwnership: Error, A1 length %u, should be %u\n", + a1Auth_length, TPM_SECRET_SIZE); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 7. Validate the command and parameters using A1 and ownerAuth, on error return TPM_AUTHFAIL + */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TakeOwnership: A1 secret", a1Auth); + returnCode = TPM_Authdata_Check(tpm_state, + a1Auth, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + 8. Validate srkParams + */ + /* a. If srkParams -> keyUsage is not TPM_KEY_STORAGE return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Validating SRK parameters\n"); + if (srkParams.keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->keyUsage is not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If srkParams -> migratable is TRUE return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_TakeOwnership: Error, srkParams->keyFlags migratable is TRUE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* c. If srkParams -> algorithmParms -> algorithmID is NOT TPM_ALG_RSA return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->algorithmID is NOT TPM_ALG_RSA\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* d. If srkParams -> algorithmParms -> encScheme is NOT TPM_ES_RSAESOAEP_SHA1_MGF1 return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->encScheme is NOT TPM_ES_RSAESOAEP_SHA1_MGF1\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* e. If srkParams -> algorithmParms -> sigScheme is NOT TPM_SS_NONE return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.sigScheme != TPM_SS_NONE) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->sigScheme is NOT TPM_SS_NONE\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* f. srkParams -> algorithmParms -> parms -> keyLength MUST be greater than or equal to + 2048, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&srkRSAKeyParms, &(srkParams.algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + if (srkRSAKeyParms->keyLength < 2048) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->parms->keyLength " + "MUST be greater than or equal to 2048\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* g .If srkParams -> algorithmParms -> parms -> exponentSize is not 0, return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkRSAKeyParms->exponent.size != 0) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->parms->exponentSize %u is not zero\n", + srkRSAKeyParms->exponent.size); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* h. If TPM_PERMANENT_FLAGS -> FIPS is TRUE */ + /* i. If srkParams -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state -> tpm_permanent_flags.FIPS) { + if (srkParams.authDataUsage == TPM_AUTH_NEVER) { + printf("TPM_Process_TakeOwnership: Error, " + "FIPS and authDataUsage is TPM_AUTH_NEVER\n"); + returnCode = TPM_NOTFIPS; + } + } + } + /* check that srkParams is TPM_KEY or TPM_KEY12 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckStruct(&ver, &srkParams); + } + /* 9. Generate K1 (SRK) according to the srkParams on error return TPM_BAD_KEY_PROPERTY */ + /* a.This includes copying PCRInfo from srkParams to K1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: SRK key length %u\n", srkRSAKeyParms->keyLength); + if (ver == 1) { + if (srkParams.tpm_pcr_info != NULL) { + TPM_PCRInfo_Trace("TPM_Process_TakeOwnership: SRK PCRs", + srkParams.tpm_pcr_info->pcrSelection, + srkParams.tpm_pcr_info->digestAtRelease); + } + else { + printf("TPM_Process_TakeOwnership: No SRK PCRs\n"); + } + } + else { + if (srkParams.tpm_pcr_info_long != NULL) { + TPM_PCRInfo_Trace("TPM_Process_TakeOwnership: SRK PCRs", + srkParams.tpm_pcr_info_long->releasePCRSelection, + srkParams.tpm_pcr_info_long->digestAtRelease); + } + else { + printf("TPM_Process_TakeOwnership: No SRK PCRs\n"); + } + } + printf("TPM_Process_TakeOwnership: Creating SRK, authDataUsage %u\n", + srkParams.authDataUsage); + /* The old keys should already be deleted from an OwnerClear, but it can't hurt to do it + again to prevent memory leaks on errors. */ + TPM_Key_Delete(srk); /* not freed, in permanent store */ + returnCode = TPM_Key_GenerateRSA(srk, + tpm_state, + NULL, /* parent key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + TPM_KEY_STORAGE, /* keyUsage */ + srkParams.keyFlags, + srkParams.authDataUsage, + &(srkParams.algorithmParms), /* TPM_KEY_PARMS */ + srkParams.tpm_pcr_info, + srkParams.tpm_pcr_info_long); + writeAllNV1 = TRUE; + } + /* 15. Create TPM_PERMANENT_DATA -> tpmProof by using the TPM RNG */ + /* NOTE: Moved here so tpmProof can be inserted into SRK -> migrationAuth */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating tpmProof\n"); + returnCode = TPM_Secret_Generate(tpm_state->tpm_permanent_data.tpmProof); + } + /* 10. Create A2 a TPM_SECRET by decrypting encSrkAuth using the PRIVEK */ + /* a. This requires A2 to be encrypted using the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptH(a2SrkAuth, /* decrypted data */ + &a2SrkAuth_length, /* actual size of A2 */ + TPM_SECRET_SIZE, /* size of A2 buffer */ + encSrkAuth.buffer, /* encrypted data */ + encSrkAuth.size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* b. Validate that A2 is a length of 20 bytes, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (a2SrkAuth_length != TPM_SECRET_SIZE) { + printf("TPM_Process_TakeOwnership: Error, A2 length %u, should be %u\n", + a2SrkAuth_length, TPM_SECRET_SIZE); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* c. Store A2 in K1 (SRK) -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TakeOwnership: Insert usageAuth into SRK", a2SrkAuth); + /* get the TPM_STORE_ASYMKEY from the TPM_KEY srk */ + returnCode = TPM_Key_GetStoreAsymkey(&srkStoreAsymkey, srk); + } + if (returnCode == TPM_SUCCESS) { + /* insert the authData into the TPM_STORE_ASYMKEY */ + TPM_Secret_Copy(srkStoreAsymkey->usageAuth, a2SrkAuth); + /* store tpmProof in migrationAuth to indicate that this is a non-migratable key */ + TPM_Secret_Copy(srkStoreAsymkey->migrationAuth, tpm_state->tpm_permanent_data.tpmProof); + /* serialize the TPM_STORE_ASYMKEY object */ + returnCode = TPM_StoreAsymkey_Store(&asymKeySbuffer, FALSE, srkStoreAsymkey); + } + /* store the serialized TPM_STORE_ASYMKEY as encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(srk->encData), &asymKeySbuffer); + } + /* 11. Store K1 in TPM_PERMANENT_DATA -> srk */ + /* NOTE Generated directly in srk */ + /* 12. Store A1 in TPM_PERMANENT_DATA -> ownerAuth */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(tpm_state->tpm_permanent_data.ownerAuth, a1Auth); + tpm_state->tpm_permanent_data.ownerInstalled = TRUE; + } + /* 13. Create TPM_PERMANENT_DATA -> contextKey according to the rules for the algorithm in use + by the TPM to save context blobs */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating contextKey\n"); + returnCode = TPM_SymmetricKeyData_GenerateKey(tpm_state->tpm_permanent_data.contextKey); + } + /* 14. Create TPM_PERMANENT_DATA -> delegateKey according to the rules for the algorithm in use + by the TPM to save delegate blobs */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating delegateKey\n"); + returnCode = TPM_SymmetricKeyData_GenerateKey(tpm_state->tpm_permanent_data.delegateKey); + } + /* 15. Create TPM_PERMANENT_DATA -> tpmProof by using the TPM RNG */ + /* NOTE: This Action done earlier */ + /* 16. Export TPM_PERMANENT_DATA -> srk as srkPub */ + if (returnCode == TPM_SUCCESS) { + /* copy the srk */ + printf("TPM_Process_TakeOwnership: Creating srkPub for response\n"); + returnCode = TPM_Key_Copy(&srkPub, srk, FALSE); /* don't copy encData */ + } + /* 17. Set TPM_PERMANENT_FLAGS -> readPubek to FALSE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Clear readPubek\n"); + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.readPubek), /* flag */ + FALSE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TakeOwnership: 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; + /* append srkPub */ + returnCode = TPM_Key_Store(response, &srkPub); + /* 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 */ + /* 18. Calculate resAuth using the newly established TPM_PERMANENT_DATA -> ownerAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthParams_Set(response, + tpm_state->tpm_permanent_data.ownerAuth, /* 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); + } + TPM_SizedBuffer_Delete(&encOwnerAuth); /* @1 */ + TPM_SizedBuffer_Delete(&encSrkAuth); /* @2 */ + TPM_Key_Delete(&srkParams); /* @3 */ + TPM_Key_Delete(&srkPub); /* @5 */ + TPM_SizedBuffer_Delete(&exponent); /* @6 */ + TPM_Sbuffer_Delete(&asymKeySbuffer); /* @7 */ + return rcf; +} + +/* 6.2 TPM_OwnerClear rev 101 + + The OwnerClear command performs the clear operation under authorization. This command is + available until the Owner executes the DisableOwnerClear, at which time any further invocation of + this command returns TPM_CLEAR_DISABLED. +*/ + +TPM_RESULT TPM_Process_OwnerClear(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_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: permanent_data.ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* 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_SECRET oldOwnerAuth; /* saved copy for response */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back permanent */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerClear: 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. Verify that the TPM Owner authorizes the command and all of the input, on error return + TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the TPM_PERMANENT_DATA.ownerAuth for the response, since it gets + invalidated in step 5. */ + TPM_Secret_Copy(oldOwnerAuth, *hmacKey); + TPM_PrintFour("TPM_Process_OwnerClear: ownerAuth secret", *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. If TPM_PERMANENT_FLAGS -> disableOwnerClear is TRUE then return TPM_CLEAR_DISABLED. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_flags.disableOwnerClear) { + printf("TPM_Process_OwnerClear: Error, disableOwnerClear is TRUE\n"); + returnCode = TPM_CLEAR_DISABLED; + } + } + /* owner clear common code */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't delete if D bit set */ + continueAuthSession = FALSE; /* Fixed value FALSE */ + writeAllNV = TRUE; + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerClear: 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, + oldOwnerAuth, /* old 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, terminate the session. NOTE: Normally this will fail because all + sessions have been closed. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 6.3 TPM_ForceClear rev 109 + + The ForceClear command performs the Clear operation under physical access. This command is + available until the execution of the DisableForceClear, at which time any further invocation of + this command returns TPM_CLEAR_DISABLED. + + TPM_ForceClear can succeed even if no owner is installed. In that case, it does whatever + TPM_OwnerClear actions that it can. +*/ + +TPM_RESULT TPM_Process_ForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ForceClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ForceClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM SHALL check for the assertion of physical presence, if not present return + TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_ForceClear: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. If TPM_STCLEAR_FLAGS -> disableForceClear is TRUE return TPM_CLEAR_DISABLED */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.disableForceClear) { + printf("TPM_Process_ForceClear: Error, disableForceClear is TRUE\n"); + returnCode = TPM_CLEAR_DISABLED; + } + } + /* 3. The TPM SHALL execute the actions of TPM_OwnerClear (except for the TPM Owner + authentication check) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't delete if D bit set */ + writeAllNV = TRUE; + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ForceClear: 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 */ + } + /* 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); + } + return rcf; +} + +/* TPM_OwnerClearCommon() rev 116 + + Performs owner clear operations common to TPM_OwnerClear, TPM_ForceClear, and TPM_RevokeTrust. + + It assumes that any required authorization is performed by the caller + + If deleteAllNvram is TRUE, all NVRAM is deleted. If it is FALSE, indexes with the D bit set are + not cleared. + + Data is not written back to NV space here. It is written by the caller. +*/ + +TPM_RESULT TPM_OwnerClearCommon(tpm_state_t *tpm_state, + TPM_BOOL deleteAllNvram) +{ + TPM_RESULT rc = 0; + size_t start; + size_t current; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + /* 3. Unload all loaded keys. */ + /* a. If TPM_PERMANENT_FLAGS -> FIPS is TRUE, the memory locations containing secret or private + keys MUST be set to all zeros. */ + start = 0; + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + printf("TPM_OwnerClearCommon: Flushing key handle %08x\n", + tpm_key_handle_entry->handle); + rc = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + start = current + 1; + } +#ifdef TPM_V11 + /* 5. The TPM sets all DIR registers to their default value. */ + if (rc == 0) { + TPM_Digest_Init(tpm_state->tpm_permanent_data.authDIR); + } +#endif + /* a.This includes owner evict keys */ + if (rc == 0) { + printf("TPM_OwnerClearCommon: Deleting owner evict keys\n"); + TPM_KeyHandleEntries_OwnerEvictDelete(tpm_state->tpm_key_handle_entries); + } + /* 4. The TPM MUST NOT modify the following TPM_PERMANENT_DATA items + a. endorsementKey + b. revMajor + c. revMinor + d. manuMaintPub + e. auditMonotonicCounter + NOTE: TPMWG email: Don't touch the base value. + f. monotonicCounter + g. pcrAttrib + h. rngState + i. EKReset + j. lastFamilyID + k. tpmDAASeed + l. DIR[1] + m. daaProof + n. daaBlobKey + */ + /* 5. The TPM MUST invalidate the following TPM_PERMANENT_DATA items and + any internal resources associated with these items */ + if (rc == 0) { + printf("TPM_OwnerClearCommon: Invalidate TPM_PERMANENT_DATA items\n"); + /* a. ownerAuth */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.ownerAuth); + tpm_state->tpm_permanent_data.ownerInstalled = FALSE; + /* b. srk */ + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.srk)); + /* c. delegateKey */ + printf("TPM_OwnerClearCommon: Invalidate delegateKey\n"); + TPM_SymmetricKeyData_Init(tpm_state->tpm_permanent_data.delegateKey); + /* d. delegateTable */ + TPM_DelegateTable_Delete(&(tpm_state->tpm_permanent_data.delegateTable)); + /* e. contextKey */ + printf("TPM_OwnerClearCommon: Invalidate contextKey\n"); + TPM_SymmetricKeyData_Init(tpm_state->tpm_permanent_data.contextKey); + /* f. tpmProof */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.tpmProof); + /* g. operatorAuth */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.operatorAuth); + /* 6. The TPM MUST reset to manufacturing defaults the following TPM_PERMANENT_DATA items */ + /* a. noOwnerNVWrite MUST be set to 0 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = 0; + /* b. ordinalAuditStatus */ + rc = TPM_OrdinalAuditStatus_Init(&(tpm_state->tpm_permanent_data)); + /* c. restrictDelegate */ + tpm_state->tpm_permanent_data.restrictDelegate = 0; + } + if (rc == 0) { + /* 7. The TPM MUST invalidate or reset all fields of TPM_STANY_DATA + a. Nonces SHALL be reset + b. Lists (e.g. contextList) SHALL be invalidated + NOTE This also terminates all sessions + */ + printf("TPM_OwnerClearCommon: Invalidate TPM_STANY_DATA\n"); + TPM_StanyData_Delete(&(tpm_state->tpm_stany_data)); + /* 8. The TPM MUST invalidate all fields of TPM_STCLEAR_DATA except the PCR's + a. Nonces SHALL be reset + b. Lists (e.g. contextList) SHALL be invalidated + c. deferredPhysicalPresence MUST be set to 0 + */ + printf("TPM_OwnerClearCommon: Invalidate TPM_STCLEAR_DATA\n"); + TPM_StclearData_Delete(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + FALSE); /* don't reset the PCR's */ + /* 9. The TPM MUST set the following TPM_PERMANENT_FLAGS to their default values */ + /* a. disable */ + printf("TPM_OwnerClearCommon: Set disable TRUE\n"); + tpm_state->tpm_permanent_flags.disable = TRUE; + /* b. deactivated */ + printf("TPM_OwnerClearCommon: Set deactivated TRUE\n"); + tpm_state->tpm_permanent_flags.deactivated = TRUE; + /* c. readPubek */ + printf("TPM_OwnerClearCommon: Set readPubek TRUE\n"); + tpm_state->tpm_permanent_flags.readPubek = TRUE; + /* d. disableOwnerClear */ + tpm_state->tpm_permanent_flags.disableOwnerClear = FALSE; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* e. disableFullDALogicInfo */ + tpm_state->tpm_permanent_flags.disableFullDALogicInfo = FALSE; +#endif + /* f. allowMaintenance */ +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + tpm_state->tpm_permanent_flags.allowMaintenance = FALSE; +#else + tpm_state->tpm_permanent_flags.allowMaintenance = TRUE; +#endif + + /* #if (TPM_REVISION >= 104) This was added in rev 104, but was implemented by vendors + earlier */ + /* g. readSRKPub */ + tpm_state->tpm_permanent_flags.readSRKPub = FALSE; + /* 10. The TPM MUST set the following TPM_PERMANENT_FLAGS */ + /* a. ownership to TRUE */ + tpm_state->tpm_permanent_flags.ownership = TRUE; + /* b. operator to FALSE */ + tpm_state->tpm_permanent_flags.tpmOperator = FALSE; + /* c. maintenanceDone to FALSE */ + tpm_state->tpm_permanent_flags.maintenanceDone = FALSE; + /* 11. The TPM releases all TPM_PERMANENT_DATA -> monotonicCounter settings + + a. This includes invalidating all currently allocated counters. The result will be no + currently allocated counters and the new owner will need to allocate counters. The actual + count value will continue to increase. + */ + rc = TPM_Counters_Release(tpm_state->tpm_permanent_data.monotonicCounter); + /* NOTE: v1.1 says to set all TPM_PERSISTENT_FLAGS to the default value, but I doubt this is + correct. I assume that physicalPresenceLifetimeLock which is a one-way flag, should not + be reset. A similar comment goes for tpmPost and tpmPostLock. */ + } + /* TPM_OwnerClear 12. The TPM MUST deallocate all defined NV storage areas where + a. TPM_NV_PER_OWNERWRITE is TRUE if nvIndex does not have the "D" bit set + b. TPM_NV_PER_OWNERREAD is TRUE if nvIndex does not have the "D" bit set + c. The TPM MUST NOT deallocate any other currently defined NV storage areas. + d.This default behavior MAY be superseded for GPIO indexes by the platform specific + specification. + + TPM_RevokeTrust: a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This + changes the TPM_OwnerClear handling of the same NV areas + */ + if (rc == 0) { + rc = TPM_NVIndexEntries_DeleteOwnerAuthorized(&(tpm_state->tpm_nv_index_entries), + deleteAllNvram); + } +#if defined TPM_PCCLIENT + /* From the PC Client TIS + + 1.When there is no TPM Owner, the TPM_NV_INDEX_GPIO_00 area MUST be deallocated (see main + specification part 3 on TPM_OwnerClear). + */ + if (rc == 0) { + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + TPM_NV_INDEX_GPIO_00); + /* if found, delete */ + if (rc == 0) { + TPM_NVDataSensitive_Delete(tpm_nv_data_sensitive); + } + else if (rc == TPM_BADINDEX) { + rc = TPM_SUCCESS; /* non-existent index is not an error */ + } + } +#endif + /* 13. The TPM MUST invalidate all familyTable entries */ + if (rc == 0) { + TPM_FamilyTable_Delete(&(tpm_state->tpm_permanent_data.familyTable)); + } + /* 14. The TPM MUST terminate all sessions, active or saved. */ + /* NOTE: Done by TPM_StclearData_Delete() */ + /* NOTE The TPM_PERMANENT_DATA and TPM_PERMANENT_FLAGS NVRAM store cannot be factored out here, + since some callers do other functions before the store. */ + return rc; +} + +/* 6.6 TSC_PhysicalPresence rev 87 + + Some TPM operations require the indication of a human's physical presence at the platform. The + presence of the human either provides another indication of platform ownership or a mechanism to + ensure that the execution of the command is not the result of a remote software process. + + This command allows a process on the platform to indicate the assertion of physical presence. As + this command is executable by software there must be protections against the improper invocation + of this command. + + The physicalPresenceHWEnable and physicalPresenceCMDEnable indicate the ability for either SW or + HW to indicate physical presence. These flags can be reset until the physicalPresenceLifetimeLock + is set. The platform manufacturer should set these flags to indicate the capabilities of the + platform the TPM is bound to. The command provides two sets of functionality. The first is to + enable, permanently, either the HW or the SW ability to assert physical presence. The second is + to allow SW, if enabled, to assert physical presence. +*/ + +TPM_RESULT TPM_Process_PhysicalPresence(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_PHYSICAL_PRESENCE physicalPresence; /* The state to set the TPM's Physical Presence + flags */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ +#ifdef TPM_V12 + uint16_t a1 = TRUE; /* lifetime settings */ + uint16_t a2 = TRUE; /* assertion settings */ +#endif + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalPresence: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get physicalPresence parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&physicalPresence, &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); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalPresence: physicalPresence parameter %04x\n", physicalPresence); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalPresence: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ +#ifdef TPM_V12 + if (returnCode == TPM_SUCCESS) { + if (physicalPresence & TPM_PHYSICAL_PRESENCE_MASK) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresence extra bits\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 1. For documentation ease, the bits break into two categories. The first is the lifetime + settings and the second is the assertion settings. */ + if (returnCode == TPM_SUCCESS) { + /* a. Define A1 to be the lifetime settings: TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK, + TPM_PHYSICAL_PRESENCE_HW_ENABLE, TPM_PHYSICAL_make contingent!!!PRESENCE_CMD_ENABLE, + TPM_PHYSICAL_PRESENCE_HW_DISABLE, and TPM_PHYSICAL_PRESENCE_CMD_DISABLE */ + a1 = physicalPresence & (TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK | + TPM_PHYSICAL_PRESENCE_HW_ENABLE | + TPM_PHYSICAL_PRESENCE_CMD_ENABLE | + TPM_PHYSICAL_PRESENCE_HW_DISABLE | + TPM_PHYSICAL_PRESENCE_CMD_DISABLE); + + /* b. Define A2 to be the assertion settings: TPM_PHYSICAL_PRESENCE_LOCK, + TPM_PHYSICAL_PRESENCE_PRESENT, and TPM_PHYSICAL_PRESENCE_NOTPRESENT */ + a2 = physicalPresence & (TPM_PHYSICAL_PRESENCE_LOCK | + TPM_PHYSICAL_PRESENCE_PRESENT | + TPM_PHYSICAL_PRESENCE_NOTPRESENT); + printf("TPM_Process_PhysicalPresence: a1 %04x a2 %04x\n", a1, a2); + } + /* + Lifetime lock settings + */ + /* 2. If any A1 setting is present */ + if ((returnCode == TPM_SUCCESS) && a1) { + if (returnCode == TPM_SUCCESS) { + /* a. If TPM_PERMANENT_FLAGS -> physicalPresenceLifetimeLock is TRUE, return + TPM_BAD_PARAMETER */ + if (tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock) { + printf("TPM_Process_PhysicalPresence: Error, " + "physicalPresenceLifetimeLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If any A2 setting is present return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (a2) { + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* c. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_ENABLE and physicalPresence -> + TPM_PHYSICAL_PRESENCE_HW_DISABLE are TRUE, return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_DISABLE)) { + printf("TPM_Process_PhysicalPresence: Error, HW enable and disable both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_ENABLE and physicalPresence + -> TPM_PHYSICAL_PRESENCE_CMD_DISABLE are TRUE, return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE ) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_DISABLE )) { + printf("TPM_Process_PhysicalPresence: Error, CMD enable and disable both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* e. If physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_ENABLE is TRUE Set + TPM_PERMANENT_FLAGS -> physicalPresenceHWEnable to TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + TRUE); /* value */ + } + /* f. If physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_DISABLE is TRUE Set + TPM_PERMANENT_FLAGS -> physicalPresenceHWEnable to FALSE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_DISABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + FALSE); /* value */ + } + /* g. If physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_ENABLE is TRUE, Set + TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable to TRUE. */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + TRUE); /* value */ + } + /* h. If physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_DISABLE is TRUE, Set + TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable to FALSE. */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_DISABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + FALSE); /* value */ + } + /* i. If physicalPresence -> TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK) { + /* i. Set TPM_PERMANENT_FLAGS -> physicalPresenceLifetimeLock to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLifetimeLock\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock), + TRUE); /* value */ + } + } + /* j. Return TPM_SUCCESS */ + } + /* + SW physical presence assertion + */ + /* 3. If any A2 setting is present */ + if ((returnCode == TPM_SUCCESS) && a2) { + /* a. If any A1 setting is present return TPM_BAD_PARAMETER */ + /* i. This check here just for consistency, the prior checks would have already ensured that + this was OK */ + if (returnCode == TPM_SUCCESS) { + if (a1) { + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable is FALSE, return TPM_BAD_PARAMETER + */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceCMDEnable is FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* c. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_LOCK and physicalPresence -> + TPM_PHYSICAL_PRESENCE_PRESENT are TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK ) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, LOCK and PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_PRESENT and physicalPresence -> + TPM_PHYSICAL_PRESENCE_NOTPRESENT are TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, PRESENT and NOT_PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* e. If TPM_STCLEAR_FLAGS -> physicalPresenceLock is TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.physicalPresenceLock) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* f. If physicalPresence -> TPM_PHYSICAL_PRESENCE_LOCK is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to FALSE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + /* ii. Set TPM_STCLEAR_FLAGS -> physicalPresenceLock to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLock TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresenceLock = TRUE; + /* iii. Return TPM_SUCCESS */ + } + /* g. If physicalPresence -> TPM_PHYSICAL_PRESENCE_PRESENT is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = TRUE; + } + /* h. If physicalPresence -> TPM_PHYSICAL_PRESENCE_NOTPRESENT is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to FALSE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + } + /* i. Return TPM_SUCCESS */ + } + } + /* 4. Else There were no A1 or A2 parameters set */ + if (returnCode == TPM_SUCCESS) { + if (!a1 && !a2) { + /* a. Return TPM_BAD_PARAMETER */ + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } +#else /* TPM v1.1 */ + /* 2. Once the PhysicalPresenceLock flag is set to TRUE, the TPM MUST not modify the + PhysicalPresence flag until a TPM_Init followed by TPM_Startup(stType = TCPA_ST_CLEAR). Upon + a TPM_Init and TPM_Startup(stType = TCPA_ST_STATE) the TPM MUST set the PhysicalPresenceLock + flag to FALSE. */ + /* NOTE: I assume this is a typo, that PhysicalPresenceLock is restored by TPM_ST_STATE and set + false on TPM_ST_CLEAR. Other places in the specification certainly say that. */ + /* 3.If the PhysicalPresenceLock flag is set to TRUE upon any call to this operation, the TPM + MUST cause no action and MUST return the error TCPA_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.physicalPresenceLock) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + /* NOTE: The specification doesn't say what to do if both flags are set. Following the 1.2 + specification seems reasonable. */ + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, PRESENT and NOT_PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + if ((tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock) && + (physicalPresence & (TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK | + TPM_PHYSICAL_PRESENCE_HW_ENABLE | + TPM_PHYSICAL_PRESENCE_CMD_ENABLE))) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLifetimeLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + if ((!tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable) && + (physicalPresence & (TPM_PHYSICAL_PRESENCE_LOCK | + TPM_PHYSICAL_PRESENCE_PRESENT | + TPM_PHYSICAL_PRESENCE_NOTPRESENT))) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceCMDEnable is FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + + } + /* 1. This operation MUST be implemented to process the values in the following order: */ + if (returnCode == TPM_SUCCESS) { + /* a. physicalPresenceHWEnable and physicalPresenceCMDEnable */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + TRUE); /* value */ + } + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + TRUE); /* value */ + } + /* b. physicalPresenceLifetimeLock */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLifetimeLock\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock), + TRUE); /* value */ + } + /* c. PhysicalPresence */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresence TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = TRUE; + } + if (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + } + /* d. PhysicalPresenceLock */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLock TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresenceLock = TRUE; + } + } +#endif + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalPresence: 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 */ + } + /* 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); + } + return rcf; +} + +/* 6.4 TPM_DisableOwnerClear rev 87 + + The DisableOwnerClear command disables the ability to execute the TPM_OwnerClear command + permanently. Once invoked the only method of clearing the TPM will require physical access to the + TPM. + + After the execution of TPM_ForceClear, ownerClear is re-enabled and must be explicitly disabled + again by the new TPM Owner. +*/ + +TPM_RESULT TPM_Process_DisableOwnerClear(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_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* 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 = NULL; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisableOwnerClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisableOwnerClear: 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 verifies that the authHandle properly authorizes the owner. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM sets the TPM_PERMANENT_FLAGS -> disableOwnerClear flag to TRUE. */ + /* 3. When this flag is TRUE the only mechanism that can clear the TPM is the TPM_ForceClear + command. The TPM_ForceClear command requires physical access to the TPM to execute. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DisableOwnerClear: Set disableOwnerClear\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disableOwnerClear), /* flag */ + TRUE); /* value */ + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisableOwnerClear: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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, 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); + } + return rcf; +} + +/* 6.5 TPM_DisableForceClear rev 97 + + The DisableForceClear command disables the execution of the ForceClear command until the next + startup cycle. Once this command is executed, the TPM_ForceClear is disabled until another + startup cycle is run. +*/ + +TPM_RESULT TPM_Process_DisableForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisableForceClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisableForceClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM sets the TPM_STCLEAR_FLAGS.disableForceClear flag in the TPM that disables the + execution of the TPM_ForceClear command. */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_stclear_flags.disableForceClear = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisableForceClear: 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 */ + } + /* 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); + } + return rcf; +} + +/* 6.7 TSC_ResetEstablishmentBit rev 98 + + The PC TPM Interface Specification (TIS) specifies setting tpmEstablished to TRUE upon execution + of the HASH_START sequence. The setting implies the creation of a Trusted Operating System on the + platform. Platforms will use the value of tpmEstablished to determine if operations necessary to + maintain the security perimeter are necessary. + + The tpmEstablished bit provides a non-volatile, secure reporting that a HASH_START was previously + run on the platform. When a platform makes use of the tpmEstablished bit, the platform can reset + tpmEstablished as the operation is no longer necessary. + + For example, a platform could use tpmEstablished to ensure that, if HASH_START had ever been, + executed the platform could use the value to invoke special processing. Once the processing is + complete the platform will wish to reset tpmEstablished to avoid invoking the special process + again. + + The TPM_PERMANENT_FLAGS -> tpmEstablished bit described in the TPM specifications uses positive + logic. The TPM_ACCESS register uses negative logic, so that TRUE is reflected as a 0. +*/ + +TPM_RESULT TPM_Process_ResetEstablishmentBit(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ResetEstablishmentBit: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ResetEstablishmentBit: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate the assertion of locality 3 or locality 4 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, /* BYTE bitmap */ + tpm_state->tpm_stany_flags.localityModifier); + } + /* 2. Set TPM_PERMANENT_FLAGS -> tpmEstablished to FALSE */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.tpmEstablished), /* flag */ + FALSE); /* value */ + + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* 3. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ResetEstablishmentBit: 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 */ + } + /* 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); + } + return rcf; +} + diff --git a/src/tpm12/tpm_owner.h b/src/tpm12/tpm_owner.h new file mode 100644 index 0000000..b96464f --- /dev/null +++ b/src/tpm12/tpm_owner.h @@ -0,0 +1,107 @@ +/********************************************************************************/ +/* */ +/* Ownership Processing */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_owner.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_OWNER_H +#define TPM_OWNER_H + +#include "tpm_global.h" +#include "tpm_secret.h" +#include "tpm_store.h" +#include "tpm_types.h" + +TPM_RESULT TPM_OwnerClearCommon(tpm_state_t *tpm_state, + TPM_BOOL deleteAllNvram); + +TPM_RESULT TPM_Process_TakeOwnership(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 TPM_Process_OwnerClear(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 TPM_Process_PhysicalPresence(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 TPM_Process_DisableOwnerClear(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 TPM_Process_ForceClear(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 TPM_Process_DisableForceClear(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 TPM_Process_ResetEstablishmentBit(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); +#endif diff --git a/src/tpm12/tpm_pcr.c b/src/tpm12/tpm_pcr.c new file mode 100644 index 0000000..b6998a7 --- /dev/null +++ b/src/tpm12/tpm_pcr.c @@ -0,0 +1,3800 @@ +/********************************************************************************/ +/* */ +/* PCR Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_pcr.c 4730 2014-09-08 22:02:18Z 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_auth.h" +#include "tpm_constants.h" +#include "tpm_cryptoh.h" +#include "tpm_digest.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_sizedbuffer.h" +#include "tpm_types.h" +#include "tpm_ver.h" + +#include "tpm_pcr.h" + + +/* + Locality Utilities +*/ + +/* TPM_Locality_Set() sets a bit in the TPM_LOCALITY_SELECTION (BYTE) bitmap based on the + TPM_STANY_FLAGS -> TPM_MODIFIER_INDICATOR (uint32_t) -> localityModifier +*/ + +TPM_RESULT TPM_Locality_Set(TPM_LOCALITY_SELECTION *tpm_locality_selection, /* BYTE bitmap */ + TPM_MODIFIER_INDICATOR tpm_modifier_indicator) /* uint32_t from + TPM_STANY_FLAGS + */ +{ + TPM_RESULT rc = 0; + printf(" TPM_Locality_Set:\n"); + switch (tpm_modifier_indicator) { + case 0: + *tpm_locality_selection = TPM_LOC_ZERO; + break; + case 1: + *tpm_locality_selection = TPM_LOC_ONE; + break; + case 2: + *tpm_locality_selection = TPM_LOC_TWO; + break; + case 3: + *tpm_locality_selection = TPM_LOC_THREE; + break; + case 4: + *tpm_locality_selection = TPM_LOC_FOUR; + break; + default: + /* This should never occur. The code that sets TPM_STANY_FLAGS should screen out bad values + */ + printf("TPM_Locality_Set: Error (fatal), tpm_modifier_indicator %u out of range\n", + tpm_modifier_indicator); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_Locality_Check() checks that a bit in the TPM_LOCALITY_SELECTION (BYTE) bitmap is set for bit + TPM_STANY_FLAGS -> TPM_MODIFIER_INDICATOR (uint32_t) -> localityModifier + + 'tpm_locality_selection' is typically localityAtRelease, pcrResetLocal, pcrExtendLocal + 'localityModifier' is TPM_STANY_FLAGS.localityModifier +*/ + +TPM_RESULT TPM_Locality_Check(TPM_LOCALITY_SELECTION tpm_locality_selection, /* BYTE bitmap */ + TPM_MODIFIER_INDICATOR localityModifier) /* uint32_t from + TPM_STANY_FLAGS */ +{ + + TPM_RESULT rc = 0; + printf(" TPM_Locality_Check:\n"); + switch (localityModifier) { + case 0: + if ((tpm_locality_selection & TPM_LOC_ZERO) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 1: + if ((tpm_locality_selection & TPM_LOC_ONE) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 2: + if ((tpm_locality_selection & TPM_LOC_TWO) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 3: + if ((tpm_locality_selection & TPM_LOC_THREE) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 4: + if ((tpm_locality_selection & TPM_LOC_FOUR) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + default: + /* This should never occur. The code that sets TPM_STANY_FLAGS should screen out bad values + */ + printf("TPM_Locality_Check: Error (fatal), localityModifier %u out of range\n", + localityModifier); + rc = TPM_FAIL; + } + if (rc != 0) { + printf("TPM_Locality_Check: Error, " + "localityModifier %u tpm_locality_selection %02x\n", + localityModifier, tpm_locality_selection); + } + return rc; +} + +TPM_RESULT TPM_LocalitySelection_CheckLegal(TPM_LOCALITY_SELECTION tpm_locality_selection) /* BYTE + bitmap */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_LocalitySelection_CheckLegal: TPM_LOCALITY_SELECTION %02x\n", + tpm_locality_selection); + /* if any extra bits are set, illegal value */ + if ((tpm_locality_selection & ~TPM_LOC_ALL) || + /* This value MUST not be zero (0). (can never be satisfied) */ + (tpm_locality_selection == 0)) { + printf("TPM_LocalitySelection_CheckLegal: Error, bad locality selection %02x\n", + tpm_locality_selection); + rc = TPM_INVALID_STRUCTURE; + } + return rc; +} + +TPM_RESULT TPM_LocalityModifier_CheckLegal(TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + + printf(" TPM_LocalityModifier_CheckLegal: TPM_MODIFIER_INDICATOR %08x\n", localityModifier); + /* if past the maximum, illegal value */ + if (localityModifier > TPM_LOC_MAX) { + printf("TPM_LocalityModifier_CheckLegal: Error, bad locality modifier %u\n", + localityModifier); + rc = TPM_BAD_LOCALITY; + } + return rc; +} + +void TPM_PCRLocality_Compare(TPM_BOOL *match, + TPM_LOCALITY_SELECTION tpm_locality_selection1, + TPM_LOCALITY_SELECTION tpm_locality_selection2) +{ + if (tpm_locality_selection1 == tpm_locality_selection2) { + *match = TRUE; + } + else { + *match = FALSE; + } + return; +} + +/* + state PCR's +*/ + +TPM_RESULT TPM_PCR_CheckRange(TPM_PCRINDEX index) +{ + TPM_RESULT rc = 0; + + if (index >= TPM_NUM_PCR) { + printf("TPM_PCR_CheckRange: Error, PCR index was %u should be <= %u\n", + index, TPM_NUM_PCR); + rc = TPM_BADINDEX; + } + return rc; +} + +/* TPM_PCR_Init() initializes the PCR based on the platform specification. This should be called by + TPM_Init. + + The caller must check that the PCR index is in range! +*/ + +void TPM_PCR_Init(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + size_t pcrIndex) +{ + printf(" TPM_PCR_Init: pcrIndex %lu\n", (unsigned long)pcrIndex); + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + tpm_pcr_attributes = tpm_pcr_attributes; + if ((pcrIndex >= 17) && (pcrIndex <= 22)) { + TPM_Digest_Set(tpm_pcrs[pcrIndex]); /* 17-22 init to ff */ + } + else { + TPM_Digest_Init(tpm_pcrs[pcrIndex]); /* 0-16,23 init to 0 */ + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (!(tpm_pcr_attributes[pcrIndex].pcrReset)) { + /* FALSE- Default value of the PCR MUST be 0x00..00 */ + TPM_Digest_Init(tpm_pcrs[pcrIndex]); + } + else { + /* TRUE - Default value of the PCR MUST be 0xFF..FF. */ + TPM_Digest_Set(tpm_pcrs[pcrIndex]); + } +#endif + return; +} + +/* TPM_PCR_Reset() resets the PCR based on the platform specification. This should be called by the + TPM_PCR_Reset ordinal. + + The caller must check that the PCR index is in range and that pcrReset is TRUE! +*/ + +void TPM_PCR_Reset(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_BOOL TOSPresent, + TPM_PCRINDEX pcrIndex) +{ + TPM_PCRVALUE zeroPCR; + TPM_PCRVALUE onesPCR; + + TPM_Digest_Init(zeroPCR); + TPM_Digest_Set(onesPCR); +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + if (TOSPresent || /* TOSPresent -> 00 */ + (pcrIndex == 16) || /* PCR 16 -> 00 */ + (pcrIndex == 23)) { /* PCR 23 -> 00 */ + TPM_PCR_Store(tpm_pcrs, pcrIndex, zeroPCR); + } + else { + TPM_PCR_Store(tpm_pcrs, pcrIndex, onesPCR); /* PCR 17-22 -> ff */ + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (TOSPresent) { + TPM_PCR_Store(tpm_pcrs, pcrIndex, zeroPCR); + } + else { + TPM_PCR_Store(tpm_pcrs, pcrIndex, onesPCR); + } +#endif + return; +} + +/* TPM_PCR_Load() copies the PCR at 'index' to 'dest_pcr' + +*/ + +TPM_RESULT TPM_PCR_Load(TPM_PCRVALUE dest_pcr, + TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index) +{ + TPM_RESULT rc = 0; + + /* range check pcrNum */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(index); + } + if (rc == 0) { + TPM_Digest_Copy(dest_pcr, tpm_pcrs[index]); + } + return rc; +} + +/* TPM_PCR_Store() copies 'src_pcr' to the PCR at 'index' + +*/ + +TPM_RESULT TPM_PCR_Store(TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index, + TPM_PCRVALUE src_pcr) +{ + TPM_RESULT rc = 0; + + /* range check pcrNum */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(index); + } + if (rc == 0) { + TPM_Digest_Copy(tpm_pcrs[index], src_pcr); + } + return rc; +} + +/* + TPM_SELECT_SIZE +*/ + +/* TPM_SelectSize_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SelectSize_Init(TPM_SELECT_SIZE *tpm_select_size) +{ + printf(" TPM_SelectSize_Init:\n"); + tpm_select_size->major = TPM_MAJOR; + tpm_select_size->minor = TPM_MINOR; + tpm_select_size->reqSize = TPM_NUM_PCR/CHAR_BIT; + return; +} + +/* TPM_SelectSize_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SelectSize_Init() +*/ + +TPM_RESULT TPM_SelectSize_Load(TPM_SELECT_SIZE *tpm_select_size, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + printf(" TPM_SelectSize_Load:\n"); + /* load major */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_select_size->major), stream, stream_size); + } + /* This SHALL indicate the major version of the TPM. This MUST be 0x01 */ + if (rc == 0) { + if (tpm_select_size->major != 0x01) { + printf("TPM_SelectSize_Load: Error, major %02x should be 01\n", tpm_select_size->major); + rc = TPM_BAD_PARAMETER; + } + } + /* load minor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_select_size->minor), stream, stream_size); + } + /* This SHALL indicate the minor version of the TPM. This MAY be 0x01 or 0x02 */ + if (rc == 0) { + if ((tpm_select_size->minor != 0x01) && + (tpm_select_size->minor != 0x02)) { + printf("TPM_SelectSize_Load: Error, minor %02x should be 01\n", tpm_select_size->minor); + rc = TPM_BAD_PARAMETER; + } + } + /* load reqSize */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_select_size->reqSize), stream, stream_size); + } + return rc; +} + +/* + TPM_PCR_ATTRIBUTES +*/ + +/* 8.9 Debug PCR register + + There is a need to define a PCR that allows for debugging. The attributes of the debug register + are such that it is easy to reset but the register provides no measurement value that can not be + spoofed. Production applications should not use the debug PCR for any SEAL or other + operations. The anticipation is that the debug PCR is set and used by application developers + during the application development cycle. Developers are responsible for ensuring that a conflict + between two programs does not invalidate the settings they are interested in. + + The specific register that is the debug PCR MUST be set by the platform specific specification. + + The attributes for the debug PCR SHALL be the following: + pcrReset = TRUE; + pcrResetLocal = 0x1f; + pcrExtendLocal = 0x1f; + pcrUseLocal = 0x1f + + These settings are to create a PCR register that developers can use to reset at any time during + their development cycle. + + The debug PCR does NOT need to be saved during TPM_SaveState. + + 8.7 PCR Attributes + + 1. The PCR attributes MUST be set during manufacturing. + + 2. For a specific PCR register, the PCR attributes MUST match the requirements of the TCG + platform specific specification that describes the platform. +*/ + +void TPM_PCRAttributes_Init(TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + size_t i; + + printf(" TPM_PCRAttributes_Init:\n"); + for (i = 0 ; i < TPM_NUM_PCR ; i++) { +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ +#if TPM_NUM_PCR != 24 +#error "Number of PCRs must be 24 for PC Client" +#endif + if (i <=15) { + tpm_pcr_attributes[i].pcrReset = FALSE; /* 0-15 are not resettable */ + tpm_pcr_attributes[i].pcrResetLocal = 0; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } + else { + tpm_pcr_attributes[i].pcrReset = TRUE; + switch (i) { + case 16: + case 23: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_ALL; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + break; + case 17: + case 18: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_FOUR | TPM_LOC_THREE | TPM_LOC_TWO; + break; + case 19: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_THREE | TPM_LOC_TWO; + break; + case 20: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR | TPM_LOC_TWO; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_THREE | TPM_LOC_TWO | TPM_LOC_ONE; + break; + case 21: + case 22: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_TWO; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_TWO; + break; + } + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (i != TPM_DEBUG_PCR) { + tpm_pcr_attributes[i].pcrReset = FALSE; + tpm_pcr_attributes[i].pcrResetLocal = 0; /* not relevant when pcrReset is FALSE */ + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } + else { /* debug PCR */ + tpm_pcr_attributes[i].pcrReset = TRUE; + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_ALL; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } +#endif + } + return; +} + +/* TPM_PCRInfo_Trace() traces some PCR Info components */ + +void TPM_PCRInfo_Trace(const char *message, + TPM_PCR_SELECTION pcrSelection, + TPM_COMPOSITE_HASH digestAtRelease) +{ + printf("%s\n", message); + printf("\tsizeOfSelect %hu\n", pcrSelection.sizeOfSelect); + printf("\tpcrSelect %02x %02x %02x\n", + pcrSelection.pcrSelect[0], + pcrSelection.pcrSelect[1], + pcrSelection.pcrSelect[2]); + TPM_PrintFour("\tdigestAtRelease", + digestAtRelease); + return; +} + +/* + PCRs - Functions that act on the entire set of PCRs +*/ + +/* TPM_PCRs_Init() initializes the entire PCR array. + + Typically called from TPM_Init. +*/ + +void TPM_PCRs_Init(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + size_t i; + + printf(" TPM_PCRs_Init:\n"); + for (i = 0 ; i < TPM_NUM_PCR ; i++) { + TPM_PCR_Init(tpm_pcrs, tpm_pcr_attributes, i); /* initialize a single PCR */ + } + return; +} + +TPM_RESULT TPM_PCRs_Load(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRs_Load:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + /* FALSE: Saved by TPM_SaveState + TRUE: MUST not be part of any state stored by TPM_SaveState */ + if (!(tpm_pcr_attributes[i].pcrReset)) { + rc = TPM_Digest_Load(tpm_pcrs[i], stream, stream_size); + } + } + return rc; +} + +TPM_RESULT TPM_PCRs_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRs_Store:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + /* FALSE: Saved by TPM_SaveState + TRUE: MUST not be part of any state stored by TPM_SaveState */ + if (!(tpm_pcr_attributes[i].pcrReset)) { + rc = TPM_Digest_Store(sbuffer, tpm_pcrs[i]); + } + } + return rc; +} + +/* + TPM_PCR_COMPOSITE +*/ + +/* TPM_PCRComposite_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_PCRComposite_Init(TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + TPM_PCRSelection_Init(&(tpm_pcr_composite->select)); + TPM_SizedBuffer_Init(&(tpm_pcr_composite->pcrValue)); + return; +} + +/* TPM_PCRComposite_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_PCRComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRComposite_Store:\n"); + + /* store TPM_PCR_SELECTION select */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_composite->select)); + } + /* store pcrValue */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_pcr_composite->pcrValue)); + } + return rc; +} + +/* TPM_PCRComposite_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PCRComposite_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_PCRComposite_Delete(TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + printf(" TPM_PCRComposite_Delete:\n"); + if (tpm_pcr_composite != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_composite->select)); + TPM_SizedBuffer_Delete(&(tpm_pcr_composite->pcrValue)); + TPM_PCRComposite_Init(tpm_pcr_composite); + } + return; +} + +/* TPM_PCRComposite_Set() + + sets members to input parameter values + allocates memory as required to fill in pointers + returns 0 or error codes + + After use, call TPM_PCRComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRComposite_Set(TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + size_t i; /* byte in map */ + size_t j; /* bit map in byte */ + size_t pcrs = 0; /* number of selected PCR's */ + TPM_PCRINDEX pcr_num; /* selected PCR being copied */ + size_t comp_num; /* index into composite */ + + printf(" TPM_PCRComposite_Set:\n"); + /* test sizeOfSelect value */ + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + /* construct the TPM_PCR_COMPOSITE structure */ + if (rc == 0) { + /* copy the TPM_PCR_SELECTION member */ + rc = TPM_PCRSelection_Copy(&(tpm_pcr_composite->select), tpm_pcr_selection); + } + /* iterate through all bytes in tpm_pcr_selection to count the number of selected PCR's */ + if (rc == 0) { + for (i = 0, pcrs = 0 ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + /* iterate through all bits in each byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1) { + if (tpm_pcr_selection->pcrSelect[i] & j) { /* if the bit is set in the map */ + pcrs++; + } + } + } + } + /* allocate memory for the pcrValue member (a TPM_PCRVALUE for each selected PCR) */ + if ((rc == 0) && (pcrs > 0)) { + printf(" TPM_PCRComposite_Set: Digesting %lu pcrs\n", (unsigned long)pcrs); + rc = TPM_SizedBuffer_Allocate(&(tpm_pcr_composite->pcrValue), pcrs * sizeof(TPM_PCRVALUE)); + } + /* Next iterate through all bytes in tpm_pcr_selection and copy to TPM_PCR_COMPOSITE */ + if ((rc == 0) && (pcrs > 0)) { + for (i = 0, pcr_num = 0, comp_num = 0 ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + /* iterate through all bits in each byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1, pcr_num++) { + if (tpm_pcr_selection->pcrSelect[i] & j) { /* if the bit is set in the map */ + printf(" TPM_PCRComposite_Set: Adding PCR %u\n", pcr_num); + /* append the the PCR value to TPM_PCR_COMPOSITE.pcrValue */ + /* NOTE: Ignore return code since range checked by + TPM_PCRSelection_CheckRange() */ + TPM_PCR_Load(&(tpm_pcr_composite->pcrValue.buffer[comp_num]), + tpm_pcrs, pcr_num); + comp_num += sizeof(TPM_PCRVALUE); + } + } + } + } + return rc; +} + +/* + TPM_PCR_INFO_SHORT +*/ + +void TPM_PCRInfoShort_Init(TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + TPM_PCRSelection_Init(&(tpm_pcr_info_short->pcrSelection)); + tpm_pcr_info_short->localityAtRelease = TPM_LOC_ALL; + TPM_Digest_Init(tpm_pcr_info_short->digestAtRelease); + return; +} + +/* TPM_PCRInfoShort_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + optimize invokes a special version used to an load TPM_NV_DATA_PUBLIC that may not include + digestAtRelease + + After use, call TPM_PCRInfoShort_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoShort_Load(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage = TRUE; + + printf(" TPM_PCRInfoShort_Load:\n"); + /* load pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_short->pcrSelection), stream, stream_size); + } + /* load the localityAtRelease */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_short->localityAtRelease), stream, stream_size); + } + /* check locality value */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_short->localityAtRelease); + } + /* if the store was optimized, check whether the pcrSelection specifies PCRs */ + if ((rc == 0) && optimize) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, + &(tpm_pcr_info_short->pcrSelection), + 0); /* start_index */ + } + /* load the digestAtRelease */ + if (rc == 0) { + if (pcrUsage) { + rc = TPM_Digest_Load(tpm_pcr_info_short->digestAtRelease, stream, stream_size); + } + /* A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is + not required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the + digest can return zero. A TPM that does store the digest may return either the digest or + zero. Software should not be written to depend on either implementation. + */ + else { + TPM_Digest_Init(tpm_pcr_info_short->digestAtRelease); + } + } + return rc; +} + +/* TPM_PCRInfoShort_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + optimize invokes a special version used to an store TPM_NV_DATA_PUBLIC that may not include + digestAtRelease + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoShort_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage = TRUE; + + printf(" TPM_PCRInfoShort_Store:\n"); + /* store pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_short->pcrSelection)); + } + /* store the localityAtRelease */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_short->localityAtRelease), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* check whether the pcrSelection specifies PCRs */ + if ((rc == 0) && optimize) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, + &(tpm_pcr_info_short->pcrSelection), + 0); /* start_index */ + } + /* store the digestAtRelease */ + /* A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is + not required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the + digest can return zero. A TPM that does store the digest may return either the digest or + zero. Software should not be written to depend on either implementation. + */ if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_short->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoShort_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRInfoShort + sets pointers to NULL + calls TPM_PCRInfoShort_Init to set members back to default values + The PCRInfoShort itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRInfoShort_Delete(TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + printf(" TPM_PCRInfoShort_Delete:\n"); + if (tpm_pcr_info_short != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info_short->pcrSelection)); + TPM_PCRInfoShort_Init(tpm_pcr_info_short); + } + return; +} + +/* TPM_PCRInfoShort_Create() allocates memory for a TPM_PCR_INFO_SHORT + +*/ + +TPM_RESULT TPM_PCRInfoShort_Create(TPM_PCR_INFO_SHORT **tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO_SHORT structure has already been + loaded. This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info_short != NULL) { + printf("TPM_PCRInfoShort_Create: Error (fatal), TPM_PCR_INFO_SHORT already loaded\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info_short, sizeof(TPM_PCR_INFO_SHORT)); + } + return rc; +} + +/* TPM_PCRInfoShort_SetFromBuffer() sets a TPM_PCR_INFO_SHORT from a stream specified by a + TPM_SIZED_BUFFER. The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoShort_LoadFromBuffer(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfoShort_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfoShort_Init(tpm_pcr_info_short); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO_SHORT structure */ + rc = TPM_PCRInfoShort_Load(tpm_pcr_info_short, &stream, &stream_size, FALSE); + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromBuffer() allocates the TPM_PCR_INFO_SHORT structure, typically a cache + within another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromBuffer(TPM_PCR_INFO_SHORT **tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO_SHORT - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(tpm_pcr_info_short); + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_LoadFromBuffer(*tpm_pcr_info_short, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfoShort_Copy() copies the source pcrSelection, digestAtRelease, and digestAtCreation. + +*/ + +TPM_RESULT TPM_PCRInfoShort_Copy(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_SHORT *src_tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_Copy:\n"); + /* copy TPM_PCR_SELECTION pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info_short->pcrSelection)); + } + if (rc == 0) { + /* copy TPM_LOCALITY_SELECTION localityAtRelease */ + dest_tpm_pcr_info_short->localityAtRelease = src_tpm_pcr_info_short->localityAtRelease; + /* copy TPM_COMPOSITE_HASH digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info_short->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoShort_CopyInfo() copies the source TPM_PCR_INFO to the destination TPM_PCR_INFO_SHORT. + + It copies pcrSelection and digestAtRelease. + + It handles localityAtRelease as per the specification. +*/ + +TPM_RESULT TPM_PCRInfoShort_CopyInfo(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CopyInfo:\n"); + /* 4. To set IS from IN */ + /* a. Set IS -> pcrSelection to IN -> pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info->pcrSelection)); + } + /* b. Set IS -> digestAtRelease to IN -> digestAtRelease */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info->digestAtRelease); + /* c. Set IS -> localityAtRelease to 0x1F to indicate all localities are valid */ + dest_tpm_pcr_info_short->localityAtRelease = TPM_LOC_ALL; + /* d. Ignore IN -> digestAtCreation */ + } + return rc; +} + +/* TPM_PCRInfoShort_CopyInfoLong() copies the source TPM_PCR_INFO_LONG to the destination + TPM_PCR_INFO_SHORT. + + It copies creationPCRSelection, localityAtRelease, digestAtRelease. +*/ + +TPM_RESULT TPM_PCRInfoShort_CopyInfoLong(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CopyInfoLong:\n"); + /* 5. To set IS from IL */ + /* a. Set IS -> pcrSelection to IL -> releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* b. Set IS -> localityAtRelease to IL -> localityAtRelease */ + if (rc == 0) { + dest_tpm_pcr_info_short->localityAtRelease = src_tpm_pcr_info_long->localityAtRelease; + /* c. Set IS -> digestAtRelease to IL -> digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + /* d. Ignore all other IL values */ + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromInfo() allocates memory for the TPM_PCR_INFO_SHORT structure. It + copies the source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromInfo(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromInfo:\n"); + if (rc == 0) { + /* if there is no source, leave the destination NULL */ + if (src_tpm_pcr_info == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(dest_tpm_pcr_info_short); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_CopyInfo(*dest_tpm_pcr_info_short, src_tpm_pcr_info); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromInfoLong(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromInfoLong:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(dest_tpm_pcr_info_short); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_CopyInfoLong(*dest_tpm_pcr_info_short, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromKey() allocates memory for the TPM_PCR_INFO_SHORT structure. + + If the input is a TPM_KEY, it copies the TPM_PCR_INFO cache. + + If the input is a TPM_KEY12, it copies the TPM_PCR_INFO_LONG cache. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromKey(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CreateFromKey:\n"); + if (rc == 0) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfoShort_CreateFromInfo(dest_tpm_pcr_info_short, + tpm_key->tpm_pcr_info); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoShort_CreateFromInfoLong(dest_tpm_pcr_info_short, + tpm_key->tpm_pcr_info_long); + } + } + return rc; +} + +/* TPM_PCRInfoShort_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfoShort_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO_SHORT *tpm_pcr_info_short, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfoShort_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info_short == NULL) { + printf("TPM_PCRInfoShort_GenerateDigest: Error (fatal), TPM_PCR_INFO_SHORT is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info_short->pcrSelection); /* get the TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfoShort_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION and + compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfoShort_CheckDigest(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfoShort_CheckDigest:\n"); + /* returns FALSE if tpm_pcr_info_short is NULL or selection bitmap is zero */ + if (rc == 0) { + rc = TPM_PCRInfoShort_GetPCRUsage(&pcrUsage, tpm_pcr_info_short); + } + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info_short -> + pcrSelection */ + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info_short->pcrSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to tpm_pcr_info_short -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info_short->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfoShort_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + /* If localityAtRelease is NOT 0x1f */ + if ((rc == 0) && (tpm_pcr_info_short != NULL)) { + if (tpm_pcr_info_short->localityAtRelease != TPM_LOC_ALL) { + /* Validate that TPM_STANY_FLAGS -> localityModifier is matched by tpm_pcr_info_short -> + localityAtRelease on mismatch return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_pcr_info_short->localityAtRelease, + localityModifier); + } + } + return rc; +} + +/* TPM_PCRInfoShort_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. Returns FALSE if the TPM_PCR_INFO_SHORT is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_GetPCRUsage\n"); + if (rc == 0) { + /* if a loaded key had no pcrInfoShort, the structure remains NULL */ + if (tpm_pcr_info_short == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, &(tpm_pcr_info_short->pcrSelection), 0); + } + if (rc == 0) { + printf(" TPM_PCRInfoShort_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + +/* + TPM_PCR_INFO +*/ + +void TPM_PCRInfo_Init(TPM_PCR_INFO *tpm_pcr_info) +{ + TPM_PCRSelection_Init(&(tpm_pcr_info->pcrSelection)); + TPM_Digest_Init(tpm_pcr_info->digestAtRelease); + TPM_Digest_Init(tpm_pcr_info->digestAtCreation); + return; +} + +/* TPM_PCRInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_PCRInfo_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfo_Load(TPM_PCR_INFO *tpm_pcr_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Load:\n"); + /* load pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info->pcrSelection), stream, stream_size); + } + /* load the digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info->digestAtRelease, stream, stream_size); + } + /* load the digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info->digestAtCreation, stream, stream_size); + } + return rc; +} + +/* TPM_PCRInfo_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_PCRInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO *tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Store:\n"); + /* store pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info->pcrSelection)); + } + /* store digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info->digestAtRelease); + } + /* store digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRInfo + sets pointers to NULL2 + calls TPM_PCRInfo_Init to set members back to default values + The PCRInfo itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRInfo_Delete(TPM_PCR_INFO *tpm_pcr_info) +{ + printf(" TPM_PCRInfo_Delete:\n"); + if (tpm_pcr_info != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info->pcrSelection)); + TPM_PCRInfo_Init(tpm_pcr_info); + } + return; +} + +/* TPM_PCRInfo_Create() allocates memory for a TPM_PCR_INFO + +*/ + +TPM_RESULT TPM_PCRInfo_Create(TPM_PCR_INFO **tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO structure has already been loaded. + This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info != NULL) { + printf("TPM_PCRInfo_Create: Error (fatal), TPM_PCR_INFO already loaded\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info, sizeof(TPM_PCR_INFO)); + } + return rc; +} + +/* TPM_PCRInfo_LoadFromBuffer() sets a TPM_PCR_INFO from a stream specified by a TPM_SIZED_BUFFER. + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfo_LoadFromBuffer(TPM_PCR_INFO *tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfo_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfo_Init(tpm_pcr_info); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO structure */ + rc = TPM_PCRInfo_Load(tpm_pcr_info, &stream, &stream_size); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromBuffer() allocates the TPM_PCR_INFO structure, typically a cache within + another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + If the stream is empty, a NULL is returned. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromBuffer(TPM_PCR_INFO **tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(tpm_pcr_info); + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_LoadFromBuffer(*tpm_pcr_info, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfo_Copy() copies the source to the destination. + + It copies pcrSelection, digestAtRelease, and digestAtCreation. +*/ + +TPM_RESULT TPM_PCRInfo_Copy(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Copy:\n"); + /* copy TPM_PCR_SELECTION pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info->pcrSelection), + &(src_tpm_pcr_info->pcrSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtRelease, + src_tpm_pcr_info->digestAtRelease); + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtCreation, + src_tpm_pcr_info->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfo_CopyInfoLong() copies the source TPM_PCR_INFO_LONG to the destination TPM_PCR_INFO. + + It copies pcrSelection and digestAtRelease. + + It handles digestAtCreation as per the specification. +*/ + +TPM_RESULT TPM_PCRInfo_CopyInfoLong(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL selectMatch; + TPM_BOOL localityMatch; + + printf(" TPM_PCRInfo_Copy:\n"); + /* 9. To set IN from IL */ + /* a. Set IN -> pcrSelection to IL -> releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info->pcrSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + /* b. Set IN -> digestAtRelease to IL -> digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + TPM_PCRSelection_Compare(&selectMatch, + &(src_tpm_pcr_info_long->creationPCRSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + TPM_PCRLocality_Compare(&localityMatch, + src_tpm_pcr_info_long->localityAtCreation, + src_tpm_pcr_info_long->localityAtRelease); + /* c. If IL -> creationPCRSelection and IL -> localityAtCreation both match IL -> + releasePCRSelection and IL -> localityAtRelease */ + if (selectMatch && localityMatch) { + /* i. Set IN -> digestAtCreation to IL -> digestAtCreation */ + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtCreation, + src_tpm_pcr_info_long->digestAtCreation); + } + /* d. Else */ + else { + /* i. Set IN -> digestAtCreation to NULL */ + TPM_Digest_Init(dest_tpm_pcr_info->digestAtCreation); + } + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfo() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromInfo(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromInfo:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(dest_tpm_pcr_info); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Copy(*dest_tpm_pcr_info, src_tpm_pcr_info); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromInfoLong(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromInfoLong:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(dest_tpm_pcr_info); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_CopyInfoLong(*dest_tpm_pcr_info, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromKey() allocates memory for the TPM_PCR_INFO structure. + + If the input is a TPM_KEY, it copies the TPM_PCR_INFO cache. + + If the input is a TPM_KEY12, it copies the TPM_PCR_INFO_LONG cache. + + If the source is NULL, the destination is NULL. +*/ + + +TPM_RESULT TPM_PCRInfo_CreateFromKey(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_CreateFromKey:\n"); + if (rc == 0) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(dest_tpm_pcr_info, tpm_key->tpm_pcr_info); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfo_CreateFromInfoLong(dest_tpm_pcr_info, tpm_key->tpm_pcr_info_long); + } + } + return rc; +} + +/* TPM_PCRInfo_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfo_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO *tpm_pcr_info, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfo_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info == NULL) { + printf("TPM_PCRInfo_GenerateDigest: Error (fatal), TPM_PCR_INFO is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info->pcrSelection); /* get the TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfo_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION + and compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfo_CheckDigest(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfo_CheckDigest:\n"); + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info -> pcrSelection */ + if (rc == 0) { + rc = TPM_PCRInfo_GetPCRUsage(&pcrUsage, tpm_pcr_info, 0); + } + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info->pcrSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfo_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + return rc; +} + +/* TPM_PCRInfo_SetDigestAtCreation() calculates a digestAtCreation based on the TPM_PCR_SELECTION + already set in the TPM_PCR_INFO structure. +*/ + +TPM_RESULT TPM_PCRInfo_SetDigestAtCreation(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_SetDigestAtCreation:\n"); + if (rc == 0) { + rc = TPM_PCRInfo_GenerateDigest(tpm_pcr_info->digestAtCreation, tpm_pcr_info, tpm_pcrs); + } + return rc; +} + +/* TPM_PCRInfo_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_PCRInfo_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO *tpm_pcr_info, + size_t start_index) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (rc == 0) { + /* if a loaded key had no pcrInfo, the structure remains NULL */ + if (tpm_pcr_info == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, &(tpm_pcr_info->pcrSelection), start_index); + } + if (rc == 0) { + printf(" TPM_PCRInfo_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + +/* + TPM_PCR_INFO_LONG +*/ + +/* TPM_PCRInfoLong_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_PCRInfoLong_Init(TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + printf(" TPM_PCRInfoLong_Init:\n"); +/* tpm_pcr_info_long->tag = TPM_TAG_PCR_INFO_LONG; */ + tpm_pcr_info_long->localityAtCreation = TPM_LOC_ZERO; + tpm_pcr_info_long->localityAtRelease = TPM_LOC_ALL; + TPM_PCRSelection_Init(&(tpm_pcr_info_long->creationPCRSelection)); + TPM_PCRSelection_Init(&(tpm_pcr_info_long->releasePCRSelection)); + TPM_Digest_Init(tpm_pcr_info_long->digestAtCreation); + TPM_Digest_Init(tpm_pcr_info_long->digestAtRelease); + return; +} + +/* TPM_PCRInfoLong_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_PCRInfoLong_Init() + After use, call TPM_PCRInfoLong_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoLong_Load(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_PCR_INFO_LONG, stream, stream_size); + } + /* load localityAtCreation */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_long->localityAtCreation), stream, stream_size); + } + /* check locality value. The TPM MAY treat a localityAtCreation value of 0 as an error. */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_long->localityAtCreation); + } + /* load localityAtRelease */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_long->localityAtRelease), stream, stream_size); + } + /* check locality value */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_long->localityAtRelease); + } + /* load creationPCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_long->creationPCRSelection), stream, stream_size); + } + /* load releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_long->releasePCRSelection), stream, stream_size); + } + /* load digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info_long->digestAtCreation, stream, stream_size); + } + /* load digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info_long->digestAtRelease, stream, stream_size); + } + return rc; +} + +/* TPM_PCRInfoLong_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_PCRInfoLong_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PCR_INFO_LONG); + } + /* store localityAtCreation */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_long->localityAtCreation), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* store localityAtRelease */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_long->localityAtRelease), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* store creationPCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_long->creationPCRSelection)); + } + /* store releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_long->releasePCRSelection)); + } + /* store digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_long->digestAtCreation); + } + /* store digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_long->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoLong_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PCRInfoLong_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_PCRInfoLong_Delete(TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + printf(" TPM_PCRInfoLong_Delete:\n"); + if (tpm_pcr_info_long != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info_long->creationPCRSelection)); + TPM_PCRSelection_Delete(&(tpm_pcr_info_long->releasePCRSelection)); + TPM_PCRInfoLong_Init(tpm_pcr_info_long); + } + return; +} + +/* TPM_PCRInfoLong_Create() allocates memory for a TPM_PCR_INFO_LONG + +*/ + +TPM_RESULT TPM_PCRInfoLong_Create(TPM_PCR_INFO_LONG **tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO_LONG structure has already been + loaded. This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info_long != NULL) { + printf("TPM_PCRInfoLong_Create: Error (fatal), TPM_PCR_INFO_LONG already loaded\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info_long, sizeof(TPM_PCR_INFO_LONG)); + } + return rc; +} + +/* TPM_PCRInfoLong_LoadFromBuffer() sets a TPM_PCR_INFO_LONG from a stream specified by a + TPM_SIZED_BUFFER. The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoLong_LoadFromBuffer(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfoLong_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfoLong_Init(tpm_pcr_info_long); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO_LONG structure */ + rc = TPM_PCRInfoLong_Load(tpm_pcr_info_long, &stream, &stream_size); + } + return rc; +} + +/* TPM_PCRInfoLong_CreateFromBuffer() allocates the TPM_PCR_INFO_LONG structure, typically a cache + within another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + If the stream is empty, a NULL is returned. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoLong_CreateFromBuffer(TPM_PCR_INFO_LONG **tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO_LONG - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + /* allocate memory for the buffer */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Create(tpm_pcr_info_long); + } + /* deserialize the input stream */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_LoadFromBuffer(*tpm_pcr_info_long, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfoLong_Copy() copies the source to the destination */ + +TPM_RESULT TPM_PCRInfoLong_Copy(TPM_PCR_INFO_LONG *dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Copy:\n"); + if (rc == 0) { + /* copy the localityAtCreation, localityAtRelease */ + dest_tpm_pcr_info_long->localityAtCreation = src_tpm_pcr_info_long->localityAtCreation; + dest_tpm_pcr_info_long->localityAtRelease = src_tpm_pcr_info_long->localityAtRelease; + /* copy TPM_PCR_SELECTION creationPCRSelection */ + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_long->creationPCRSelection), + &(src_tpm_pcr_info_long->creationPCRSelection)); + } + if (rc == 0) { + /* copy TPM_PCR_SELECTION releasePCRSelection*/ + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_long->releasePCRSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info_long->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + TPM_Digest_Copy(dest_tpm_pcr_info_long->digestAtCreation, + src_tpm_pcr_info_long->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfoLong_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO_LONG structure. It + copies the source tag, localityAtCreation, localityAtRelease, creationPCRSelection, + releasePCRSelection digestAtCreation, and digestAtRelease. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoLong_CreateFromInfoLong(TPM_PCR_INFO_LONG **dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_CreateFromInfoLong:\n"); + if (rc == 0) { + /* if there is no source, leave the destination NULL */ + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Create(dest_tpm_pcr_info_long); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Copy(*dest_tpm_pcr_info_long, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfoLong_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfoLong_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfoLong_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info_long == NULL) { + printf("TPM_PCRInfoLong_GenerateDigest: Error (fatal), TPM_PCR_INFO_LONG is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info_long->creationPCRSelection); /* get TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfoLong_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION + and compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfoLong_CheckDigest(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfoLong_CheckDigest:\n"); + /* returns FALSE if tpm_pcr_info_long is NULL or selection bitmap is zero */ + if (rc == 0) { + rc = TPM_PCRInfoLong_GetPCRUsage(&pcrUsage, tpm_pcr_info_long, 0); + } + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info_long -> + releasePCRSelection */ + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info_long->releasePCRSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to tpm_pcr_info_long -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info_long->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfoLong_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + /* If localityAtRelease is NOT 0x1f */ + if ((rc == 0) && (tpm_pcr_info_long != NULL)) { + if (tpm_pcr_info_long->localityAtRelease != TPM_LOC_ALL) { + /* Validate that TPM_STANY_FLAGS -> localityModifier is matched by tpm_pcr_info_short -> + localityAtRelease on mismatch return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_pcr_info_long->localityAtRelease, localityModifier); + } + } + return rc; +} + +/* TPM_PCRInfoLong_SetDigestAtCreation() calculates a digestAtCreation based on the + TPM_PCR_SELECTION creationPCRSelection already set in the TPM_PCR_INFO_LONG structure. +*/ + +TPM_RESULT TPM_PCRInfoLong_SetDigestAtCreation(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_SetDigestAtCreation:\n"); + if (rc == 0) { + rc = TPM_PCRInfoLong_GenerateDigest(tpm_pcr_info_long->digestAtCreation, + tpm_pcr_info_long, + tpm_pcrs); + } + return rc; +} + +/* TPM_PCRInfoLong_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. Returns FALSE if the TPM_PCR_INFO_LONG is NULL. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_PCRInfoLong_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + size_t start_index) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_GetPCRUsage: Start %lu\n", (unsigned long)start_index);; + if (rc == 0) { + /* if a loaded key had no pcrInfo, the structure remains NULL */ + if (tpm_pcr_info_long == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, + &(tpm_pcr_info_long->releasePCRSelection), start_index); + } + if (rc == 0) { + printf(" TPM_PCRInfoLong_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + + +/* + TPM_PCR_SELECTION +*/ + +void TPM_PCRSelection_Init(TPM_PCR_SELECTION *tpm_pcr_selection) +{ + size_t i; + + printf(" TPM_PCRSelection_Init:\n"); + tpm_pcr_selection->sizeOfSelect = TPM_NUM_PCR/CHAR_BIT; + for (i = 0 ; i < (TPM_NUM_PCR/CHAR_BIT) ; i++) { + tpm_pcr_selection->pcrSelect[i] = 0; + } + return; +} + +/* TPM_PCRSelection_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_PCRSelection_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRSelection_Load(TPM_PCR_SELECTION *tpm_pcr_selection, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_Load:\n"); + /* load sizeOfSelect */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_pcr_selection->sizeOfSelect), stream, stream_size); + } + /* test sizeOfSelect value */ + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + /* load pcrSelect map */ + for (i = 0 ; (rc == 0) && (i < tpm_pcr_selection->sizeOfSelect) ; i++) { + rc = TPM_Load8(&(tpm_pcr_selection->pcrSelect[i]), stream, stream_size); + } + /* if there was insufficient input, zero the rest of the map */ + for ( ; (rc == 0) && (i < (TPM_NUM_PCR/CHAR_BIT)) ; i++) { + rc = tpm_pcr_selection->pcrSelect[i] = 0; + } + return rc; +} + +/* TPM_PCRSelection_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_PCRSelection_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_SELECTION *tpm_pcr_selection) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRSelection_Store:\n"); + /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_pcr_selection->sizeOfSelect); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_pcr_selection->pcrSelect, tpm_pcr_selection->sizeOfSelect); + } + return rc; +} + + +/* TPM_PCRSelection_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRSelection + sets pointers to NULL + calls TPM_PCRSelection_Init to set members back to default values + The PCRSelection itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRSelection_Delete(TPM_PCR_SELECTION *tpm_pcr_selection) +{ + printf(" TPM_PCRSelection_Delete:\n"); + if (tpm_pcr_selection != NULL) { + TPM_PCRSelection_Init(tpm_pcr_selection); + } + return; +} + +/* TPM_PCRSelection_Copy() copies the source to the destination + + It returns an error if the source -> sizeOfSelect is too large. If the source is smaller than + the internally defined, fixed size of the destination, the remainder of the destination is filled + with 0's. +*/ + +TPM_RESULT TPM_PCRSelection_Copy(TPM_PCR_SELECTION *destination, TPM_PCR_SELECTION *source) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_Copy:\n"); + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(source); + } + if (rc == 0) { + /* copy sizeOfSelect member */ + destination->sizeOfSelect = source->sizeOfSelect; + /* copy pcrSelect map up to the size of the source */ + for (i = 0 ; i < source->sizeOfSelect ; i++) { + destination->pcrSelect[i] = source->pcrSelect[i]; + } + /* if the input wasn't sufficient, zero the rest of the map */ + for ( ; i < (TPM_NUM_PCR/CHAR_BIT) ; i++) { + destination->pcrSelect[i] = 0; + } + } + return rc; +} + +/* TPM_PCRSelection_GenerateDigest() generates a digest based on the TPM_PCR_SELECTION and the + current TPM PCR values. + + It internally generates a TPM_PCR_COMPOSITE according to Part 2 5.4.1. To return this structure + as well, use TPM_PCRSelection_GenerateDigest2(). +*/ + +TPM_RESULT TPM_PCRSelection_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection + map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_COMPOSITE tpm_pcr_composite; /* structure to be hashed */ + + printf(" TPM_PCRSelection_GenerateDigest:\n"); + TPM_PCRComposite_Init(&tpm_pcr_composite); /* freed @1 */ + rc = TPM_PCRSelection_GenerateDigest2(tpm_digest, + &tpm_pcr_composite, + tpm_pcr_selection, + tpm_pcrs); + TPM_PCRComposite_Delete(&tpm_pcr_composite); /* @1 */ + return rc; +} + +/* TPM_PCRSelection_GenerateDigest2() generates a digest based on the TPM_PCR_SELECTION and the + current TPM PCR values. + + It first generates a TPM_PCR_COMPOSITE according to Part 2 5.4.1. That structure is also + returned. + + TPM_PCR_COMPOSITE should be initialized and deleted by the caller. To generate and delete the + structure internally, use TPM_PCRSelection_GenerateDigest(). +*/ + +TPM_RESULT TPM_PCRSelection_GenerateDigest2(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_COMPOSITE *tpm_pcr_composite, /* output + structure + */ + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection + map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage; + + printf(" TPM_PCRSelection_GenerateDigest2:\n"); + /* assemble the TPM_PCR_COMPOSITE structure */ + if (rc == 0) { + rc = TPM_PCRComposite_Set(tpm_pcr_composite, tpm_pcr_selection, tpm_pcrs); + } + if (rc == 0) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, tpm_pcr_selection, 0); + } + if (rc == 0) { + printf(" TPM_PCRSelection_GenerateDigest2: pcrUsage %02x\n", pcrUsage); + if (pcrUsage) { + /* serialize and hash TPM_PCR_COMPOSITE */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_digest, tpm_pcr_composite, + (TPM_STORE_FUNCTION_T)TPM_PCRComposite_Store); + } + } + /* 4. If TPM_PCR_SELECTION.pcrSelect is all 0's */ + /* a. a.For digestAtCreation, the TPM MUST set TPM_COMPOSITE_HASH to be all 0's. */ + else { + TPM_Digest_Init(tpm_digest); + } + } + return rc; +} + +/* TPM_PCRSelection_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[]. +*/ + +TPM_RESULT TPM_PCRSelection_GetPCRUsage(TPM_BOOL *pcrUsage, + const TPM_PCR_SELECTION *tpm_pcr_selection, + size_t start_index) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + if (rc == 0) { + *pcrUsage = FALSE; + /* If sizeOfSelect is 0 or start_index is past the end, this loop won't be entered and FALSE + will be returned */ + for (i = start_index ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + if (tpm_pcr_selection->pcrSelect[i] != 0) { /* is any bit set in the mask */ + *pcrUsage = TRUE; + break; + } + } + } + return rc; +} + +/* TPM_PCRSelection_CheckRange() checks the sizeOfSelect index + +*/ + +TPM_RESULT TPM_PCRSelection_CheckRange(const TPM_PCR_SELECTION *tpm_pcr_selection) +{ + TPM_RESULT rc = 0; + + if (tpm_pcr_selection->sizeOfSelect > (TPM_NUM_PCR/CHAR_BIT)) { + printf("TPM_PCRSelection_CheckRange: Error, sizeOfSelect %u must be 0 - %u\n", + tpm_pcr_selection->sizeOfSelect, TPM_NUM_PCR/CHAR_BIT); + rc = TPM_INVALID_PCR_INFO; + } + return rc; +} + +/* TPM_PCRSelection_Compare() compares the TPM_PCR_SELECTION's for equality + +*/ + +void TPM_PCRSelection_Compare(TPM_BOOL *match, + TPM_PCR_SELECTION *tpm_pcr_selection1, + TPM_PCR_SELECTION *tpm_pcr_selection2) +{ + size_t i; + *match = TRUE; + + if (tpm_pcr_selection1->sizeOfSelect != tpm_pcr_selection2->sizeOfSelect) { + *match = FALSE; + } + for (i = 0 ; *match && (i < tpm_pcr_selection1->sizeOfSelect) ; i++) { + if (tpm_pcr_selection1->pcrSelect[i] != tpm_pcr_selection2->pcrSelect[i]) { + *match = FALSE; + } + } + return; +} + +#if 0 +/* TPM_PCRSelection_LessThan() compares the new selection to the old selection. It returns lessThan + TRUE is the new selection does not select a PCR that was selected by the old selection. +*/ + +void TPM_PCRSelection_LessThan(TPM_BOOL *lessThan, + TPM_PCR_SELECTION *tpm_pcr_selection_new, + TPM_PCR_SELECTION *tpm_pcr_selection_old) +{ + size_t i; + *lessThan = TRUE; + + if (tpm_pcr_selection_new->sizeOfSelect != tpm_pcr_selection_old->sizeOfSelect) { + *lessThan = FALSE; + } + for (i = 0 ; *lessThan && (i < tpm_pcr_selection_new->sizeOfSelect) ; i++) { + /* if there's a 0 in the new selection and a 1 on the old selection */ + if (~(tpm_pcr_selection_new->pcrSelect[i]) & tpm_pcr_selection_old->pcrSelect[i]) { + *lessThan = FALSE; + } + } + return; +} +#endif + + +/* + TPM_QUOTE_INFO +*/ + +/* TPM_QuoteInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_QuoteInfo_Init(TPM_QUOTE_INFO *tpm_quote_info) +{ + printf(" TPM_QuoteInfo_Init:\n"); + TPM_StructVer_Init(&(tpm_quote_info->version)); + memcpy(&(tpm_quote_info->fixed), "QUOT", 4); + TPM_Digest_Init(tpm_quote_info->digestValue); + TPM_Nonce_Init(tpm_quote_info->externalData); + return; +} + +#if 0 +/* TPM_QuoteInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_QuoteInfo_Init() + After use, call TPM_QuoteInfo_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_QuoteInfo_Load(TPM_QUOTE_INFO *tpm_quote_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo_Load:\n"); + /* load version */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_quote_info->version), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_quote_info->version)); + } + /* load fixed */ + if (rc == 0) { + rc = TPM_Loadn(tpm_quote_info->fixed, 4, stream, stream_size); + } + /* load digestValue */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_quote_info->digestValue, stream, stream_size); + } + /* load externalData */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_quote_info->externalData, stream, stream_size); + } + return rc; +} +#endif + +/* TPM_QuoteInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_QuoteInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO *tpm_quote_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo_Store:\n"); + /* store version */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_quote_info->version)); + } + /* store fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_quote_info->fixed, 4); + } + /* store digestValue */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_quote_info->digestValue); + } + /* store externalData */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_quote_info->externalData); + } + return rc; +} + +/* TPM_QuoteInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_QuoteInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_QuoteInfo_Delete(TPM_QUOTE_INFO *tpm_quote_info) +{ + printf(" TPM_QuoteInfo_Delete:\n"); + if (tpm_quote_info != NULL) { + TPM_QuoteInfo_Init(tpm_quote_info); + } + return; +} + +/* + TPM_QUOTE_INFO2 +*/ + +/* TPM_QuoteInfo2_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_QuoteInfo2_Init(TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + printf(" TPM_QuoteInfo2_Init:\n"); + memcpy(tpm_quote_info2->fixed, "QUT2", 4); + TPM_Nonce_Init(tpm_quote_info2->externalData); + TPM_PCRInfoShort_Init(&(tpm_quote_info2->infoShort)); + return; +} + +#if 0 +/* TPM_QuoteInfo2_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_QuoteInfo2_Init() + After use, call TPM_QuoteInfo2_Delete() to free memory +*/ + +TPM_RESULT TPM_QuoteInfo2_Load(TPM_QUOTE_INFO2 *tpm_quote_info2, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo2_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_QUOTE_INFO2, stream, stream_size); + } + /* load fixed */ + if (rc == 0) { + rc = TPM_Loadn(tpm_quote_info2->fixed, 4, stream, stream_size); + } + /* load externalData */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_quote_info2->externalData, stream, stream_size); + } + /* load infoShort */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_quote_info2->infoShort), stream, stream_size, FALSE); + } + return rc; +} +#endif + +/* TPM_QuoteInfo2_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_QuoteInfo2_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo2_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_QUOTE_INFO2); + } + /* store fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_quote_info2->fixed, 4); + } + /* store externalData */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_quote_info2->externalData); + } + /* store infoShort */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_quote_info2->infoShort), FALSE); + } + return rc; +} + +/* TPM_QuoteInfo2_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_QuoteInfo2_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_QuoteInfo2_Delete(TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + printf(" TPM_QuoteInfo2_Delete:\n"); + if (tpm_quote_info2 != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_quote_info2->infoShort)); + TPM_QuoteInfo2_Init(tpm_quote_info2); + } + return; +} + +/* + Command Processing Functions +*/ + + +/* 16.2 TPM_PCRRead rev 109 + + The TPM_PCRRead operation provides non-cryptographic reporting of the contents of a named PCR. +*/ + +TPM_RESULT TPM_Process_PcrRead(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_PCRINDEX pcrIndex; /* Index of the PCR to be read */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCRVALUE outDigest; + + printf("TPM_Process_PcrRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrIndex, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PcrRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1.Validate that pcrIndex represents a legal PCR number. On error, return TPM_BADINDEX. */ + /* 2. Set outDigest to TPM_STCLEAR_DATA -> PCR[pcrIndex] */ + /* NOTE Done by TPM_PCR_Load() */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PcrRead: pcrIndex %u\n", pcrIndex); + returnCode = TPM_PCR_Load(outDigest, + tpm_state->tpm_stclear_data.PCRS, + pcrIndex); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_PcrRead: PCR value", outDigest); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PcrRead: 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; + /* append outDigest */ + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 16.3 TPM_Quote rev 101 + + The TPM_Quote operation provides cryptographic reporting of PCR values. A loaded key is required + for operation. TPM_Quote uses a key to sign a statement that names the current value of a chosen + PCR and externally supplied data (which may be a nonce supplied by a Challenger). + + The term "ExternalData" is used because an important use of TPM_Quote is to provide a digital + signature on arbitrary data, where the signature includes the PCR values of the platform at time + of signing. Hence the "ExternalData" is not just for anti-replay purposes, although it is (of + course) used for that purpose in an integrity challenge. +*/ + +TPM_RESULT TPM_Process_Quote(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can sign + the PCR values. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data (typically a nonce + provided by a server to prevent replay-attacks) */ + TPM_PCR_SELECTION targetPCR; /* The indices of the PCRs that are to be reported. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA privAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key -> usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_QUOTE_INFO q1QuoteInfo; + TPM_DIGEST q1_digest; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCR_COMPOSITE pcrData; /* A structure containing the same indices as + targetPCR, plus the corresponding current PCR + values. */ + TPM_SIZED_BUFFER sig; /* The signed data blob. */ + + printf("TPM_Process_Quote: Ordinal Entry\n"); + TPM_PCRSelection_Init(&targetPCR); /* freed @1 */ + TPM_PCRComposite_Init(&pcrData); /* freed @2 */ + TPM_QuoteInfo_Init(&q1QuoteInfo); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get externalData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(externalData, &command, ¶mSize); + } + /* get targetPCR parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_Quote: externalData", externalData); + returnCode = TPM_PCRSelection_Load(&targetPCR, &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, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_Quote: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Quote: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Quote: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the authorization to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO,, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_Quote: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Quote: Error, keyUsage %04hx is invalid\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Validate targetPCR */ + /* a. targetPCR is a valid TPM_PCR_SELECTION structure */ + /* b. On errors return TPM_INVALID_PCR_INFO */ + /* NOTE: done during TPM_PCRSelection_Load() */ + /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the PCRs indicated by targetPCR -> + pcrSelect */ + /* NOTE TPM_PCRSelection_GenerateDigest2() generates the TPM_PCR_COMPOSITE as well. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest2(q1QuoteInfo.digestValue, + &pcrData, /* TPM_PCR_COMPOSITE */ + &targetPCR, + tpm_state->tpm_stclear_data.PCRS); + } + /* 6. Create Q1 a TPM_QUOTE_INFO structure */ + /* a. Set Q1 -> version to 1.1.0.0 */ + /* b. Set Q1 -> fixed to "QUOT" */ + /* NOTE: done at TPM_QuoteInfo_Init() */ + /* c. Set Q1 -> digestValue to H1 */ + /* NOTE: Generated directly in Q1 */ + /* d. Set Q1 -> externalData to externalData */ + if (returnCode == TPM_SUCCESS) { + TPM_Nonce_Copy(q1QuoteInfo.externalData, externalData); + } + /* 7. Sign SHA-1 hash of Q1 using keyHandle as the signature key */ + /* digest Q1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(q1_digest, &q1QuoteInfo, + (TPM_STORE_FUNCTION_T)TPM_QuoteInfo_Store); + } + /* sign the Q1 digest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + q1_digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Quote: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the pcrData */ + returnCode = TPM_PCRComposite_Store(response, &pcrData); + } + /* 8. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&targetPCR); /* @1 */ + TPM_PCRComposite_Delete(&pcrData); /* @2 */ + TPM_QuoteInfo_Delete(&q1QuoteInfo); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + + +/* 16.5 TPM_Quote2 rev 96 + + The TPM_Quote operation provides cryptographic reporting of PCR values. A loaded key is required + for operation. TPM_Quote uses a key to sign a statement that names the current value of a chosen + PCR and externally supplied data (which may be a nonce supplied by a Challenger). + + The term "ExternalData" is used because an important use of TPM_Quote is to provide a digital + signature on arbitrary data, where the signature includes the PCR values of the platform at time + of signing. Hence the "ExternalData" is not just for anti-replay purposes, although it is (of + course) used for that purpose in an integrity challenge. + + Quote2 differs from quote in that Quote2 uses TPM_PCR_INFO_SHORT to hold information relative to + the PCR registers. INFO_SHORT includes locality information to provide the requester a more + complete view of the current platform configuration. +*/ + +TPM_RESULT TPM_Process_Quote2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can sign + the PCR values. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data (typically a nonce + provided by a server to prevent replay-attacks) */ + TPM_PCR_SELECTION targetPCR; /* The indices of the PCRs that are to be reported. */ + TPM_BOOL addVersion; /* When TRUE add TPM_CAP_VERSION_INFO to the output */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest for inputs and + keyHandle. HMAC key: key -> usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_COMPOSITE_HASH h1CompositeHash; + TPM_QUOTE_INFO2 q1; + TPM_PCR_INFO_SHORT *s1 = NULL; + TPM_STORE_BUFFER q1_sbuffer; + TPM_STORE_BUFFER versionInfo_sbuffer; + const unsigned char *versionInfo_buffer; + TPM_DIGEST q1_digest; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t versionInfoSize; /* Size of the version info */ + TPM_CAP_VERSION_INFO versionInfo; /* The version info */ + TPM_SIZED_BUFFER sig; /* The signed data blob. */ + + printf("TPM_Process_Quote2: Ordinal Entry\n"); + TPM_PCRSelection_Init(&targetPCR); /* freed @1 */ + TPM_CapVersionInfo_Set(&versionInfo, &(tpm_state->tpm_permanent_data)); /* freed @2 */ + TPM_SizedBuffer_Init(&sig); /* freed @3 */ + TPM_QuoteInfo2_Init(&q1); /* freed @4 */ + TPM_Sbuffer_Init(&q1_sbuffer); /* freed @5 */ + TPM_Sbuffer_Init(&versionInfo_sbuffer); /* freed @6 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get externalData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote2: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(externalData, &command, ¶mSize); + } + /* get targetPCR parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_Quote2: externalData", externalData); + returnCode = TPM_PCRSelection_Load(&targetPCR, &command, ¶mSize); + } + /* get addVersion parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&addVersion, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote2: addVersion %02x\n", addVersion); + } + /* 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) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_Quote2: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Quote2: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Quote2: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1, if not return + TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_Quote2: Error, inappropriate signature scheme %04x\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Quote2: Error, keyUsage %04hx is invalid\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Validate targetPCR is a valid TPM_PCR_SELECTION structure, on errors return + TPM_INVALID_PCR_INFO */ + /* NOTE: done during TPM_PCRSelection_Load() */ + /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the PCRs indicated by targetPCR -> + pcrSelect */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest(h1CompositeHash, + &targetPCR, + tpm_state->tpm_stclear_data.PCRS); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Create S1 a TPM_PCR_INFO_SHORT */ + s1 = &(q1.infoShort); + /* a. Set S1->pcrSelection to pcrSelect */ + returnCode = TPM_PCRSelection_Copy(&(s1->pcrSelection), &targetPCR); + } + /* b. Set S1->localityAtRelease to TPM_STANY_DATA -> localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1->localityAtRelease), + tpm_state->tpm_stany_flags.localityModifier); + } + /* c. Set S1->digestAtRelease to H1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(s1->digestAtRelease, h1CompositeHash); + /* 7. Create Q1 a TPM_QUOTE_INFO2 structure */ + /* a. Set Q1 -> fixed to "QUT2" */ + /* NOTE: done at TPM_QuoteInfo2_Init() */ + /* b. Set Q1 -> infoShort to S1 */ + /* NOTE: created S1 in place */ + /* c. Set Q1 -> externalData to externalData */ + TPM_Nonce_Copy(q1.externalData, externalData); + /* serialize q1 */ + returnCode = TPM_QuoteInfo2_Store(&q1_sbuffer, &q1); + } + if (returnCode == TPM_SUCCESS) { + /* 8. If addVersion is TRUE */ + if (addVersion) { + if (returnCode == TPM_SUCCESS) { + /* a. Concatenate to Q1 a TPM_CAP_VERSION_INFO structure */ + /* b. Set the output parameters for versionInfo */ + /* serialize versionInfo. The result cannot be added directly to q1_sbuffer because + it is needed as an outgoing parameter */ + /* NOTE: Created at TPM_CapVersionInfo_Set() */ + returnCode = TPM_CapVersionInfo_Store(&versionInfo_sbuffer, &versionInfo); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialized results */ + TPM_Sbuffer_Get(&versionInfo_sbuffer, &versionInfo_buffer, &versionInfoSize); + /* concatenate TPM_CAP_VERSION_INFO versionInfo to TPM_QUOTE_INFO2 q1 buffer */ + returnCode = TPM_Sbuffer_Append(&q1_sbuffer, versionInfo_buffer, versionInfoSize); + } + } + /* 9. Else */ + else { + /* a. Set versionInfoSize to 0 */ + versionInfoSize = 0; + /* b. Return no bytes in versionInfo */ + /* NOTE Done at response, (&& addVersion) */ + } + } + /* 10. Sign a SHA-1 hash of Q1 using keyHandle as the signature key */ + /* hash q1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1Sbuffer(q1_digest, &q1_sbuffer); + } + /* sign the Q1 digest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + q1_digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Quote2: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the TPM_PCR_INFO_SHORT pcrData */ + returnCode = TPM_PCRInfoShort_Store(response, s1, FALSE); + } + /* An email clarification said that, if addVersion is FALSE, a versionInfoSize is 0 is + returned. This indicates the missing versionInfo. */ + /* return the versionInfoSize */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, versionInfoSize); + } + /* return the versionInfo */ + if ((returnCode == TPM_SUCCESS) && addVersion) { + returnCode = TPM_Sbuffer_Append(response, versionInfo_buffer, versionInfoSize); + } + /* 11. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&targetPCR); /* @1 */ + TPM_CapVersionInfo_Delete(&versionInfo); /* @2 */ + TPM_SizedBuffer_Delete(&sig); /* @3 */ + TPM_QuoteInfo2_Delete(&q1); /* @4 */ + TPM_Sbuffer_Delete(&q1_sbuffer); /* @5 */ + TPM_Sbuffer_Delete(&versionInfo_sbuffer); /* @6 */ + return rcf; +} + +/* TPM_ExtendCommon() rev 109 + + Contains code common to TPM_Process_Extend() and TPM_Process_SHA1CompleteExtend(). + + Add a measurement value to a PCR +*/ + +TPM_RESULT TPM_ExtendCommon(TPM_PCRVALUE outDigest, /* The PCR value after execution of + the command */ + tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, /* command ordinal */ + TPM_PCRINDEX pcrNum, /* Index of the PCR to be modified */ + TPM_DIGEST inDigest) /* the event to be recorded */ +{ + TPM_RESULT rc = 0; + TPM_PCRVALUE currentPcrValue; + TPM_DIGEST h1; + + printf("TPM_ExtendCommon: pcrNum %u\n", pcrNum); + /* 1. Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(pcrNum); + } + if (rc == 0) { + /* 2. Map V1 to TPM_STANY_FLAGS */ + /* 3. Map L1 to V1 -> localityModifier */ + /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> + pcrAttrib[PCRIndex].pcrExtendLocal, return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_state->tpm_permanent_data.pcrAttrib[pcrNum].pcrExtendLocal, + tpm_state->tpm_stany_flags.localityModifier); + } + /* get the current PCR digest value */ + if (rc == 0) { + rc = TPM_PCR_Load(currentPcrValue, + tpm_state->tpm_stclear_data.PCRS, + pcrNum); + } +#if defined TPM_PCCLIENT + /* From the PC Client TIS spec + + 1. When the locality 4 PCR is at its reset value of 0, the entry for the locality 4 PCR in + section 7.2 SHALL be interpreted as if the column labeled pcrExtendLocal for locality + 4,3,2,1,0 contains the bit field definitions: 1,0,0,0,0. + + 2. Once the locality 4 PCR is no longer at its reset value of 0, table 4 in section 7.2 + applies as written. + */ + if (rc == 0) { + TPM_BOOL isZero; + if ((pcrNum == 17) && /* PCR 17 is the Locality 4 PCR */ + (tpm_state->tpm_stany_flags.localityModifier != 4)) { + /* if not locality 4, must not be at the reset value */ + TPM_Digest_IsZero(&isZero, currentPcrValue); + if (isZero) { + printf("TPM_ExtendCommon: Error, " + "pcrNum %u and locality %u and PCR at reset value\n", + pcrNum, tpm_state->tpm_stany_flags.localityModifier); + rc = TPM_BAD_LOCALITY; + } + } + } +#endif + /* 5. Create c1 by concatenating (PCRindex TPM_PCRVALUE || inDigest). This takes the current PCR + value and concatenates the inDigest parameter. */ + /* NOTE: Not required, SHA1 uses varargs */ + /* 6. Create h1 by performing a SHA-1 digest of c1. */ + if (rc == 0) { + TPM_PrintFour("TPM_ExtendCommon: Current PCR ", currentPcrValue); + /* TPM_PrintFour("TPM_ExtendCommon: Current PCR ", + tpm_state->tpm_stclear_data.PCR[pcrNum]); */ + TPM_PrintFour("TPM_ExtendCommon: Input Digest", inDigest); + rc = TPM_SHA1(h1, + TPM_DIGEST_SIZE, currentPcrValue, + TPM_DIGEST_SIZE, inDigest, + 0, NULL); + } + if (rc == 0) { + TPM_PrintFour("TPM_ExtendCommon: New PCR", h1); + /* 7. Store h1 as the new TPM_PCRVALUE of PCRindex */ + rc = TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, + pcrNum, + h1); + } + if (rc == 0) { + /* 8. If TPM_PERMANENT_FLAGS -> disable is TRUE or TPM_STCLEAR_FLAGS -> deactivated is + TRUE */ + if ((tpm_state->tpm_permanent_flags.disable) || + (tpm_state->tpm_stclear_flags.deactivated)) { + /* a. Set outDigest to 20 bytes of 0x00 */ + TPM_Digest_Init(outDigest); + } + /* 9. Else */ + else { + /* a. Set outDigest to h1 */ + TPM_Digest_Copy(outDigest, h1); + } + } + if (rc == 0) { + ordinal = ordinal; + } + return rc; +} + +/* 16.1 TPM_Extend rev 109 + + This adds a new measurement to a PCR. +*/ + +TPM_RESULT TPM_Process_Extend(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_PCRINDEX pcrNum; /* The PCR to be updated. */ + TPM_DIGEST inDigest; /* The 160 bit value representing the event to be + recorded. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ + + printf("TPM_Process_Extend: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrNum parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); + } + /* get inDigest parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(inDigest, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Extend: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* extend the resultant digest into a PCR */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, inDigest); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Extend: 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; + /* append outDigest */ + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 16.4 TPM_PCR_Reset rev 87 + + For PCR with the pcrReset attribute set to TRUE, this command resets the PCR back to the default + value, this mimics the actions of TPM_Init. The PCR may have restrictions as to which locality + can perform the reset operation. + + Sending a null pcrSelection results in an error is due to the requirement that the command + actually do something. If pcrSelection is null there are no PCR to reset and the command would + then do nothing. + + For PCR that are resettable, the presence of a Trusted Operating System (TOS) can change the + behavior of TPM_PCR_Reset. The following pseudo code shows how the behavior changes + + At TPM_Startup + If TPM_PCR_ATTRIBUTES->pcrReset is FALSE + Set PCR to 0x00...00 + Else + Set PCR to 0xFF...FF + + At TPM_PCR_Reset + If TPM_PCR_ATTRIBUTES->pcrReset is TRUE + If TOSPresent + Set PCR to 0x00...00 + Else + Set PCR to 0xFF...FF + Else + Return error + + The above pseudocode is for example only, for the details of a specific platform, the reader must + review the platform specific specification. The purpose of the above pseudocode is to show that + both pcrReset and the TOSPresent bit control the value in use to when the PCR resets. +*/ + +TPM_RESULT TPM_Process_PcrReset(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_PCR_SELECTION pcrSelection; /* The PCR's to reset*/ + + /* 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 pcrUsage; /* TRUE if pcrSelection specifies one or more + PCR's */ + TPM_PERMANENT_DATA *tpm_permanent_data = NULL; + size_t i; /* PCR selection iterator */ + size_t j; /* PCR selection bit map in byte */ + TPM_PCRINDEX pcr_num; /* PCR iterator */ + TPM_MODIFIER_INDICATOR localityModifier = 0; + uint16_t sizeOfSelect = 0; /* from pcrSelection input parameter */ + + /* output parameters */ + uint16_t outParamStart; /* starting point of outParam's */ + uint16_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PcrReset: Ordinal Entry\n"); + TPM_PCRSelection_Init(&pcrSelection); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrSelection */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_Load(&pcrSelection, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PcrReset: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that pcrSelection is valid */ + /* a. is a valid TPM_PCR_SELECTION structure */ + /* NOTE: Done during TPM_PCRSelection_Load() */ + /* b. pcrSelection -> pcrSelect is non-zero */ + /* NOTE: TPM_PCRSelection_GetPCRUsage() range checks pcrSelection */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PcrReset: Getting input PCR usage\n"); + returnCode = TPM_PCRSelection_GetPCRUsage(&pcrUsage, &pcrSelection, 0); + } + /* c. On errors return TPM_INVALID_PCR_INFO */ + if (returnCode == TPM_SUCCESS) { + if (!pcrUsage) { + printf("TPM_Process_PcrReset: Error, pcrSelect is zero\n"); + returnCode = TPM_INVALID_PCR_INFO; + } + } + /* 2. Map L1 to TPM_STANY_FLAGS -> localityModifier (NOTE and other optimizations of the inner + loop) */ + if (returnCode == TPM_SUCCESS) { + localityModifier = tpm_state->tpm_stany_flags.localityModifier; + tpm_permanent_data = &(tpm_state->tpm_permanent_data); + sizeOfSelect = pcrSelection.sizeOfSelect; /* bytes of input PCR selection */ + } + /* 3. For each PCR selected perform the following */ + for (i = 0, pcr_num = 0 ; (returnCode == TPM_SUCCESS) && (i < sizeOfSelect) ; i++) { + /* iterate through all bits in each selection byte */ + for (j = 0x0001 ; + (returnCode == TPM_SUCCESS) && (j != (0x0001 << CHAR_BIT)) ; + j <<= 1, pcr_num++) { + + if (pcrSelection.pcrSelect[i] & j) { /* if the bit is set in the selection map */ + /* a. If pcrAttrib[pcrIndex].pcrReset is FALSE */ + if (!(tpm_permanent_data->pcrAttrib[pcr_num].pcrReset)) { + printf("TPM_Process_PcrReset: Error, PCR %u not resettable\n", pcr_num); + /* a. Return TPM_NOTRESETABLE */ + returnCode = TPM_NOTRESETABLE; + } + /* b. If, for the value L1, the corresponding bit is clear in the bit map + TPM_PERMANENT_DATA -> pcrAttrib[pcrIndex].pcrResetLocal, return + TPM_NOTLOCAL */ + else { + returnCode = + TPM_Locality_Check(tpm_permanent_data->pcrAttrib[pcr_num].pcrResetLocal, + localityModifier); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_PcrReset: Error, PCR %u bad pcrResetLocal %02x\n", + pcr_num, tpm_permanent_data->pcrAttrib[pcr_num].pcrResetLocal); + returnCode = TPM_NOTLOCAL; + } + } + /* NOTE: No 'else reset' here. The command MUST validate that all PCR registers + that are selected are available to be reset before resetting any PCR. */ + } + } + } + /* 3. For each PCR selected perform the following */ + if (returnCode == TPM_SUCCESS) { + for (i = 0, pcr_num = 0 ; i < sizeOfSelect ; i++) { + /* iterate through all bits in each selection byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1, pcr_num++) { + if (pcrSelection.pcrSelect[i] & j) { /* if the bit is set in the selection map */ + printf("TPM_Process_PcrReset: Resetting PCR %u\n", pcr_num); + /* a. The PCR MAY only reset to 0x00...00 or 0xFF...FF */ + /* b. The logic to determine which value to use MUST be described by a platform + specific specification + */ + /* Ignore errors here since PCR selection has already been validated. pcr_num + is guaranteed to be in range from from 'for' iterator, and pcrReset is + guaranteed to be TRUE from the previous loop. */ + TPM_PCR_Reset(tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.TOSPresent, + pcr_num); + } + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PcrReset: 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&pcrSelection); /* @1 */ + return rcf; +} + diff --git a/src/tpm12/tpm_pcr.h b/src/tpm12/tpm_pcr.h new file mode 100644 index 0000000..6036c9d --- /dev/null +++ b/src/tpm12/tpm_pcr.h @@ -0,0 +1,367 @@ +/********************************************************************************/ +/* */ +/* PCR Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_pcr.h 4620 2011-09-07 21:43:19Z 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. */ +/********************************************************************************/ + +#ifndef TPM_PCR_H +#define TPM_PCR_H + +#include "tpm_global.h" +#include "tpm_sizedbuffer.h" +#include "tpm_store.h" + +/* + Locality Utilities +*/ + +TPM_RESULT TPM_Locality_Set(TPM_LOCALITY_SELECTION *tpm_locality_selection, + TPM_MODIFIER_INDICATOR tpm_modifier_indicator); +TPM_RESULT TPM_Locality_Check(TPM_LOCALITY_SELECTION tpm_locality_selection, + TPM_MODIFIER_INDICATOR localityModifier); + +TPM_RESULT TPM_LocalitySelection_CheckLegal(TPM_LOCALITY_SELECTION tpm_locality_selection); +TPM_RESULT TPM_LocalityModifier_CheckLegal(TPM_MODIFIER_INDICATOR localityModifier); + +void TPM_PCRLocality_Compare(TPM_BOOL *match, + TPM_LOCALITY_SELECTION tpm_locality_selection1, + TPM_LOCALITY_SELECTION tpm_locality_selection2); + +/* + state PCR's +*/ + +TPM_RESULT TPM_PCR_CheckRange(TPM_PCRINDEX index); +void TPM_PCR_Init(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + size_t pcrIndex); +void TPM_PCR_Reset(TPM_PCRVALUE *tpm_pcrs, + TPM_BOOL TOSPresent, + TPM_PCRINDEX pcrIndex); +TPM_RESULT TPM_PCR_Load(TPM_PCRVALUE dest_pcr, + TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index); +TPM_RESULT TPM_PCR_Store(TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index, + TPM_PCRVALUE src_pcr); + +/* + TPM_SELECT_SIZE +*/ + +void TPM_SelectSize_Init(TPM_SELECT_SIZE *tpm_select_size); +TPM_RESULT TPM_SelectSize_Load(TPM_SELECT_SIZE *tpm_select_size, + unsigned char **stream, + uint32_t *stream_size); + + +/* + TPM_PCR_SELECTION +*/ + +void TPM_PCRSelection_Init(TPM_PCR_SELECTION *tpm_pcr_selection); +TPM_RESULT TPM_PCRSelection_Load(TPM_PCR_SELECTION *tpm_pcr_selection, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRSelection_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_SELECTION *tpm_pcr_selection); +void TPM_PCRSelection_Delete(TPM_PCR_SELECTION *tpm_pcr_selection); +/* copy */ +TPM_RESULT TPM_PCRSelection_Copy(TPM_PCR_SELECTION *destination, + TPM_PCR_SELECTION *source); +/* setters */ +TPM_RESULT TPM_PCRSelection_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRSelection_GenerateDigest2(TPM_DIGEST tpm_digest, + TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRSelection_GetPCRUsage(TPM_BOOL *pcrUsage, + const TPM_PCR_SELECTION *tpm_pcr_selection, + size_t start_index); +/* checkers */ +TPM_RESULT TPM_PCRSelection_CheckRange(const TPM_PCR_SELECTION *tpm_pcr_selection); +void TPM_PCRSelection_Compare(TPM_BOOL *match, + TPM_PCR_SELECTION *tpm_pcr_selection1, + TPM_PCR_SELECTION *tpm_pcr_selection2); +#if 0 +void TPM_PCRSelection_LessThan(TPM_BOOL *lessThan, + TPM_PCR_SELECTION *tpm_pcr_selection_new, + TPM_PCR_SELECTION *tpm_pcr_selection_old); +#endif + +/* TPM_PCR_ATTRIBUTES */ + +void TPM_PCRAttributes_Init(TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); + +void TPM_PCRInfo_Trace(const char *message, + TPM_PCR_SELECTION pcrSelection, + TPM_COMPOSITE_HASH digestAtRelease); +/* + PCRs - Functions that act on the entire set of PCRs +*/ + +void TPM_PCRs_Init(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); +TPM_RESULT TPM_PCRs_Load(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRs_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); + +/* + TPM_PCR_INFO +*/ + +void TPM_PCRInfo_Init(TPM_PCR_INFO *tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_Load(TPM_PCR_INFO *tpm_pcr_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO *tpm_pcr_info); +void TPM_PCRInfo_Delete(TPM_PCR_INFO *tpm_pcr_info); +/* create */ +TPM_RESULT TPM_PCRInfo_Create(TPM_PCR_INFO **tpm_pcr_info); +/* load */ +TPM_RESULT TPM_PCRInfo_LoadFromBuffer(TPM_PCR_INFO *tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfo_CreateFromBuffer(TPM_PCR_INFO **tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfo_Copy(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_CopyInfoLong(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfo_CreateFromInfo(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_CreateFromInfoLong(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfo_CreateFromKey(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_KEY *tpm_key); + +/* setters */ +TPM_RESULT TPM_PCRInfo_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfo_CheckDigest(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfo_SetDigestAtCreation(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRInfo_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO *tpm_pcr_info, + size_t start_index); + +/* + TPM_PCR_INFO_LONG +*/ + +void TPM_PCRInfoLong_Init(TPM_PCR_INFO_LONG *tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoLong_Load(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRInfoLong_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_LONG *tpm_pcr_info_long); +void TPM_PCRInfoLong_Delete(TPM_PCR_INFO_LONG *tpm_pcr_info_long); +/* create */ +TPM_RESULT TPM_PCRInfoLong_Create(TPM_PCR_INFO_LONG **tpm_pcr_info_long); +/* load */ +TPM_RESULT TPM_PCRInfoLong_LoadFromBuffer(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfoLong_CreateFromBuffer(TPM_PCR_INFO_LONG **tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfoLong_Copy(TPM_PCR_INFO_LONG *dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoLong_CreateFromInfoLong(TPM_PCR_INFO_LONG **dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +/* setters */ +TPM_RESULT TPM_PCRInfoLong_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfoLong_CheckDigest(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs, + TPM_MODIFIER_INDICATOR localityModifier); +TPM_RESULT TPM_PCRInfoLong_SetDigestAtCreation(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRInfoLong_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + size_t start_index); + +/* + TPM_PCR_INFO_SHORT +*/ + +void TPM_PCRInfoShort_Init(TPM_PCR_INFO_SHORT *tpm_pcr_info_short); +TPM_RESULT TPM_PCRInfoShort_Load(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize); +TPM_RESULT TPM_PCRInfoShort_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_BOOL optimize); +void TPM_PCRInfoShort_Delete(TPM_PCR_INFO_SHORT *tpm_pcr_info_short); +/* create */ +TPM_RESULT TPM_PCRInfoShort_Create(TPM_PCR_INFO_SHORT **tpm_pcr_info_short); +/* load */ +TPM_RESULT TPM_PCRInfoShort_LoadFromBuffer(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfoShort_CreateFromBuffer(TPM_PCR_INFO_SHORT **tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfoShort_Copy(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_SHORT *src_tpm_pcr_info_short); +TPM_RESULT TPM_PCRInfoShort_CopyInfo(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfoShort_CopyInfoLong(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoShort_CreateFromInfo(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfoShort_CreateFromInfoLong(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoShort_CreateFromKey(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_KEY *tpm_key); + +/* setters */ +TPM_RESULT TPM_PCRInfoShort_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfoShort_CheckDigest(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs, + TPM_MODIFIER_INDICATOR localityModifier); + +/* getters */ +TPM_RESULT TPM_PCRInfoShort_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short); + +/* + TPM_PCR_COMPOSITE +*/ + +void TPM_PCRComposite_Init(TPM_PCR_COMPOSITE *tpm_pcr_composite); +TPM_RESULT TPM_PCRComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_COMPOSITE *tpm_pcr_composite); +void TPM_PCRComposite_Delete(TPM_PCR_COMPOSITE *tpm_pcr_composite); + +TPM_RESULT TPM_PCRComposite_Set(TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); + +/* + TPM_QUOTE_INFO +*/ + +void TPM_QuoteInfo_Init(TPM_QUOTE_INFO *tpm_quote_info); +#if 0 +TPM_RESULT TPM_QuoteInfo_Load(TPM_QUOTE_INFO *tpm_quote_info, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_QuoteInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO *tpm_quote_info); +void TPM_QuoteInfo_Delete(TPM_QUOTE_INFO *tpm_quote_info); + +/* + TPM_QUOTE_INFO2 +*/ + +void TPM_QuoteInfo2_Init(TPM_QUOTE_INFO2 *tpm_quote_info2); +#if 0 +TPM_RESULT TPM_QuoteInfo2_Load(TPM_QUOTE_INFO2 *tpm_quote_info2, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_QuoteInfo2_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO2 *tpm_quote_info2); +void TPM_QuoteInfo2_Delete(TPM_QUOTE_INFO2 *tpm_quote_info2); + + +/* + Common command processing +*/ + +TPM_RESULT TPM_ExtendCommon(TPM_PCRVALUE outDigest, + tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_PCRINDEX pcrNum, + TPM_DIGEST inDigest); +/* + Command Processing +*/ + +TPM_RESULT TPM_Process_PcrRead(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 TPM_Process_Quote(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 TPM_Process_Quote2(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 TPM_Process_Extend(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 TPM_Process_PcrReset(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); +#endif diff --git a/src/tpm12/tpm_permanent.c b/src/tpm12/tpm_permanent.c new file mode 100644 index 0000000..b9a6209 --- /dev/null +++ b/src/tpm12/tpm_permanent.c @@ -0,0 +1,1333 @@ +/********************************************************************************/ +/* */ +/* Permanent Flag and Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_permanent.c 4623 2011-09-28 15:15:09Z 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_audit.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvfilename.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_structures.h" +#include "tpm_types.h" +#include "tpm_svnrevision.h" + + +#include "tpm_permanent.h" + +/* + TPM_PERMANENT_FLAGS +*/ + +void TPM_PermanentFlags_Init(TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + printf(" TPM_PermanentFlags_Init:\n"); +#ifndef TPM_ENABLE_ACTIVATE + tpm_permanent_flags->disable = TRUE; +#else /* for servers, not TCG standard */ + tpm_permanent_flags->disable = FALSE; +#endif + tpm_permanent_flags->ownership = TRUE; +#ifndef TPM_ENABLE_ACTIVATE + tpm_permanent_flags->deactivated = TRUE; +#else /* for servers, not TCG standard */ + tpm_permanent_flags->deactivated = FALSE; +#endif + tpm_permanent_flags->readPubek = TRUE; + tpm_permanent_flags->disableOwnerClear = FALSE; + tpm_permanent_flags->allowMaintenance = TRUE; + tpm_permanent_flags->physicalPresenceLifetimeLock = FALSE; + tpm_permanent_flags->physicalPresenceHWEnable = FALSE; +#ifndef TPM_PP_CMD_ENABLE /* TCG standard */ + tpm_permanent_flags->physicalPresenceCMDEnable = FALSE; +#else /* 'ship' TRUE */ + tpm_permanent_flags->physicalPresenceCMDEnable = TRUE; +#endif + /* tpm_permanent_flags->CEKPUsed = ; This flag has no default value */ + tpm_permanent_flags->TPMpost = FALSE; + tpm_permanent_flags->TPMpostLock = FALSE; + tpm_permanent_flags->FIPS = FALSE; /* if TRUE, could not test no-auth commands */ + tpm_permanent_flags->tpmOperator = FALSE; + tpm_permanent_flags->enableRevokeEK = TRUE; + tpm_permanent_flags->nvLocked = FALSE; + tpm_permanent_flags->readSRKPub = FALSE; + tpm_permanent_flags->tpmEstablished = FALSE; + tpm_permanent_flags->maintenanceDone = FALSE; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + tpm_permanent_flags->disableFullDALogicInfo = FALSE; +#endif +} + +/* TPM_PermanentFlags_Load() + + deserializes the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + It is used when deserializing the structure from storage in NVRAM. +*/ + +TPM_RESULT TPM_PermanentFlags_Load(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t tpm_bitmap; + TPM_TAG permanentFlagsVersion; + + printf(" TPM_PermanentFlags_Load:\n"); + /* load the TPM_PERMANENT_FLAGS version tag from the stream */ + if (rc == 0) { + rc = TPM_Load16(&permanentFlagsVersion, stream, stream_size); + } + /* load the TPM_PERMANENT_FLAGS from the stream */ + if (rc == 0) { + rc = TPM_Load32(&tpm_bitmap, stream, stream_size); + } + /* load the TPM_PERMANENT_FLAGS from the bitmap */ + if (rc == 0) { + rc = TPM_PermanentFlags_LoadBitmap(tpm_permanent_flags, permanentFlagsVersion, tpm_bitmap); + } + return rc; +} + +/* TPM_PermanentFlags_Store() serializes the TPM_PERMANENT_FLAGS structure as a bitmap. + + It is used when serializing the structure for storage in NVRAM. +*/ + +TPM_RESULT TPM_PermanentFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) + +{ + TPM_RESULT rc = 0; + uint32_t tpm_bitmap; + + printf(" TPM_PermanentFlags_Store:\n"); + /* store the TPM_PERMANENT_FLAGS structure in a bit map */ + if (rc == 0) { + rc = TPM_PermanentFlags_StoreBitmap(&tpm_bitmap, tpm_permanent_flags); + } + /* append a TPM_PERMANENT_FLAGS version tag */ +#if (TPM_REVISION >= 103) + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_PF103); + } +#else + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_PF94); + } +#endif + /* append the bitmap to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_bitmap); + } + return rc; +} + +/* TPM_PermanentFlags_StoreBytes() serializes the TPM_PERMANENT_FLAGS structure as bytes + + */ + +TPM_RESULT TPM_PermanentFlags_StoreBytes(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentFlags_StoreBytes:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PERMANENT_FLAGS); + } + /* store disable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->disable), sizeof(BYTE)); + } + /* store ownership */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->ownership), sizeof(BYTE)); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->deactivated), sizeof(BYTE)); + } + /* store readPubek */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->readPubek), sizeof(BYTE)); + } + /* store disableOwnerClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->disableOwnerClear), sizeof(BYTE)); + } + /* store allowMaintenance */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->allowMaintenance), sizeof(BYTE)); + } + /* store physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceLifetimeLock), + sizeof(BYTE)); + } + /* store physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceHWEnable), + sizeof(BYTE)); + } + /* store physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceCMDEnable), + sizeof(BYTE)); + } + /* store CEKPUsed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->CEKPUsed), sizeof(BYTE)); + } + /* store TPMpost */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->TPMpost), sizeof(BYTE)); + } + /* store TPMpostLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->TPMpostLock), sizeof(BYTE)); + } + /* store FIPS */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->FIPS), sizeof(BYTE)); + } + /* store operator */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->tpmOperator), sizeof(BYTE)); + } + /* store enableRevokeEK */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->enableRevokeEK), sizeof(BYTE)); + } + /* store nvLocked */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->nvLocked), sizeof(BYTE)); + } + /* store readSRKPub */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->readSRKPub), sizeof(BYTE)); + } + /* store tpmEstablished */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->tpmEstablished), sizeof(BYTE)); + } + /* store maintenanceDone */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->maintenanceDone), sizeof(BYTE)); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store disableFullDALogicInfo */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_permanent_flags->disableFullDALogicInfo), sizeof(BYTE)); + } +#endif + return rc; +} + +/* TPM_PermanentFlags_LoadBitmap() loads the TPM_PERMANENT_FLAGS structure from the bit map + + permanentFlagsVersion indicates the version being loaded from NVRAM +*/ + +TPM_RESULT TPM_PermanentFlags_LoadBitmap(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + TPM_TAG permanentFlagsVersion, + uint32_t tpm_bitmap) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + if (rc == 0) { + switch (permanentFlagsVersion) { + case TPM_TAG_NVSTATE_PF94: + break; + case TPM_TAG_NVSTATE_PF103: + /* if the TPM_REVISION supports the permanentFlagsVersion, break with no error. If it + doesn't, omit the break and fall through to the unsupported case. */ +#if (TPM_REVISION >= 103) + break; +#endif + default: + /* no forward compatibility */ + printf("TPM_PermanentFlags_LoadBitmap: Error (fatal) unsupported version tag %04x\n", + permanentFlagsVersion); + rc = TPM_FAIL; + break; + } + } + printf(" TPM_PermanentFlags_LoadBitmap:\n"); + /* load disable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disable), tpm_bitmap, &pos); + } + /* load ownership */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->ownership), tpm_bitmap, &pos); + } + /* load deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->deactivated), tpm_bitmap, &pos); + } + /* load readPubek */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->readPubek), tpm_bitmap, &pos); + } + /* load disableOwnerClear */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disableOwnerClear), tpm_bitmap, &pos); + } + /* load allowMaintenance */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->allowMaintenance), tpm_bitmap, &pos); + } + /* load physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceLifetimeLock), + tpm_bitmap, &pos); + } + /* load physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceHWEnable), tpm_bitmap, &pos); + } + /* load physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceCMDEnable), tpm_bitmap, &pos); + } + /* load CEKPUsed */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->CEKPUsed), tpm_bitmap, &pos); + } + /* load TPMpost */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->TPMpost), tpm_bitmap, &pos); + } + /* load TPMpostLock */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->TPMpostLock), tpm_bitmap, &pos); + } + /* load FIPS */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->FIPS), tpm_bitmap, &pos); + } + /* load operator */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->tpmOperator), tpm_bitmap, &pos); + } + /* load enableRevokeEK */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->enableRevokeEK), tpm_bitmap, &pos); + } + /* load nvLocked */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->nvLocked), tpm_bitmap, &pos); + } + /* load readSRKPub */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->readSRKPub), tpm_bitmap, &pos); + } + /* load tpmEstablished */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->tpmEstablished), tpm_bitmap, &pos); + } + /* load maintenanceDone */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->maintenanceDone), tpm_bitmap, &pos); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + if (rc == 0) { + switch (permanentFlagsVersion) { + case TPM_TAG_NVSTATE_PF94: + /* 94 to 103, set extra flags to default value */ + tpm_permanent_flags->disableFullDALogicInfo = FALSE; + break; + case TPM_TAG_NVSTATE_PF103: + /* 103 to 103, process normally */ + /* load disableFullDALogicInfo */ + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disableFullDALogicInfo), tpm_bitmap, &pos); + break; + } + } +#endif + return rc; +} + +/* TPM_PermanentFlags_StoreBitmap() stores the TPM_PERMANENT_FLAGS structure in a bit map + + It is used when serializing the structure for storage in NVRAM and as the return to + TPM_GetCapability. +*/ + +TPM_RESULT TPM_PermanentFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + printf(" TPM_PermanentFlags_StoreBitmap:\n"); + *tpm_bitmap = 0; /* set unused bits to 0 */ + /* store disable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disable, &pos); + } + /* store ownership */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->ownership, &pos); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->deactivated, &pos); + } + /* store readPubek */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->readPubek, &pos); + } + /* store disableOwnerClear */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disableOwnerClear, &pos); + } + /* store allowMaintenance */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->allowMaintenance, &pos); + } + /* store physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceLifetimeLock, &pos); + } + /* store physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceHWEnable, &pos); + } + /* store physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceCMDEnable, &pos); + } + /* store CEKPUsed */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->CEKPUsed, &pos); + } + /* store TPMpost */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->TPMpost, &pos); + } + /* store TPMpostLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->TPMpostLock, &pos); + } + /* store FIPS */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->FIPS, &pos); + } + /* store operator */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->tpmOperator, &pos); + } + /* store enableRevokeEK */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->enableRevokeEK, &pos); + } + /* store nvLocked */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->nvLocked, &pos); + } + /* store readSRKPub */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->readSRKPub, &pos); + } + /* store tpmEstablished */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->tpmEstablished, &pos); + } + /* store maintenanceDone */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->maintenanceDone, &pos); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store disableFullDALogicInfo */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disableFullDALogicInfo, &pos); + } +#endif + return rc; +} + +/* + TPM_PERMANENT_DATA +*/ + +/* TPM_PermanentData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + + This function generates a new contextKey, delegateKey, daaBlobKey. +*/ + + +TPM_RESULT TPM_PermanentData_Init(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentData_Init:\n"); + if (rc == 0) { + tpm_permanent_data->revMajor = ((tpm_svn_revision >> 8) & 0xff); + tpm_permanent_data->revMinor = ((tpm_svn_revision ) & 0xff); + printf(" TPM_PermanentData_Init: revMajor %02x revMinor %02x\n", + tpm_permanent_data->revMajor, tpm_permanent_data->revMinor); + /* zero all secrets */ + TPM_PermanentData_Zero(tpm_permanent_data, instanceData); + +#ifndef TPM_NOMAINTENANCE + TPM_Pubkey_Init(&(tpm_permanent_data->manuMaintPub)); +#endif + TPM_Key_Init(&(tpm_permanent_data->endorsementKey)); + TPM_Key_Init(&(tpm_permanent_data->srk)); + tpm_permanent_data->contextKey = NULL; + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->contextKey)); + } + if (rc == 0) { + tpm_permanent_data->delegateKey = NULL; + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->delegateKey)); + } + if (rc == 0) { + TPM_CounterValue_Init(&(tpm_permanent_data->auditMonotonicCounter)); + TPM_Counters_Init(tpm_permanent_data->monotonicCounter); + TPM_PCRAttributes_Init(tpm_permanent_data->pcrAttrib); + rc = TPM_OrdinalAuditStatus_Init(tpm_permanent_data); + } + if (rc == 0) { + TPM_FamilyTable_Init(&(tpm_permanent_data->familyTable)); + TPM_DelegateTable_Init(&(tpm_permanent_data->delegateTable)); + tpm_permanent_data->lastFamilyID = 0; + tpm_permanent_data->noOwnerNVWrite = 0; + tpm_permanent_data->restrictDelegate = 0; + /* tpmDAASeed done by TPM_PermanentData_Zero() */ + /* daaProof done by TPM_PermanentData_Zero() */ + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->daaBlobKey)); + } + if (rc == 0) { + tpm_permanent_data->ownerInstalled = FALSE; + /* tscOrdinalAuditStatus initialized by TPM_OrdinalAuditStatus_Init() */ + /* instanceOrdinalAuditStatus initialized by TPM_OrdinalAuditStatus_Init() */ + tpm_permanent_data->allowLoadMaintPub = TRUE; + if (instanceData) { + } + } + return rc; +} + +/* TPM_PermanentData_Load() + + deserializes the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_PermanentData_Load(TPM_PERMANENT_DATA *tpm_permanent_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL tpm_bool; + + + printf(" TPM_PermanentData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_PERMANENT_DATA, stream, stream_size); + } + /* load revMajor */ + /* load revMinor */ + /* not stored, loaded from hard coded value */ + if (rc == 0) { + tpm_permanent_data->revMajor = (tpm_svn_revision >> 8) & 0xff; + tpm_permanent_data->revMinor = tpm_svn_revision & 0xff; + } + /* load tpmProof */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading tpmProof\n"); + rc = TPM_Secret_Load(tpm_permanent_data->tpmProof, stream, stream_size); + } + /* load EKReset */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->EKReset, stream, stream_size); + } + /* load ownerAuth */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading ownerAuth \n"); + rc = TPM_Secret_Load(tpm_permanent_data->ownerAuth, stream, stream_size); + } + /* load operatorAuth */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_permanent_data->operatorAuth, stream, stream_size); + } + /* load authDIR */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_permanent_data->authDIR, stream, stream_size); + } + /* load manuMaintPub present marker */ + if (rc == 0) { + rc = TPM_Load8(&tpm_bool, stream, stream_size); + } +#ifndef TPM_NOMAINTENANCE + /* check that manuMaintPub is present */ + if (rc == 0) { + if (!tpm_bool) { + printf(" TPM_PermanentData_Load: Error (fatal) missing manuMaintPub\n"); + rc = TPM_FAIL; + } + } + /* load manuMaintPub */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load manuMaintPub\n"); + rc = TPM_Pubkey_Load(&(tpm_permanent_data->manuMaintPub), stream, stream_size); + } +#else + /* check that manuMaintPub is absent */ + if (tpm_bool) { + printf(" TPM_PermanentData_Load: Error (fatal) contains manuMaintPub\n"); + rc = TPM_FAIL; + } +#endif + /* load endorsementKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load endorsement key\n"); + rc = TPM_Key_LoadClear(&(tpm_permanent_data->endorsementKey), TRUE, stream, stream_size); + } + /* load srk */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load SRK\n"); + rc = TPM_Key_LoadClear(&(tpm_permanent_data->srk), FALSE, stream, stream_size); + } + /* load contextKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load contextKey\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->contextKey, stream, stream_size); + } + /* load delegateKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load delegateKey\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->delegateKey, stream, stream_size); + } + /* load auditMonotonicCounter */ + if (rc == 0) { + rc = TPM_CounterValue_Load(&(tpm_permanent_data->auditMonotonicCounter), + stream, stream_size); + } + /* load monotonicCounter's */ + if (rc == 0) { + rc = TPM_Counters_Load(tpm_permanent_data->monotonicCounter, stream, stream_size); + } + /* load pcrAttrib's, since they are constants, no need to load from NV space */ + if (rc == 0) { + TPM_PCRAttributes_Init(tpm_permanent_data->pcrAttrib); + } + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load ordinalAuditStatus\n"); + } + /* load ordinalAuditStatus's */ + for (i = 0 ; (rc == 0) && (i < (TPM_ORDINALS_MAX/CHAR_BIT)) ; i++) { + rc = TPM_Load8(&(tpm_permanent_data->ordinalAuditStatus[i]), stream, stream_size); + } + /* load familyTable */ + if (rc == 0) { + rc = TPM_FamilyTable_Load(&(tpm_permanent_data->familyTable), stream, stream_size); + } + /* load delegateTable */ + if (rc == 0) { + rc = TPM_DelegateTable_Load(&(tpm_permanent_data->delegateTable), stream, stream_size); + } + /* load lastFamilyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->lastFamilyID), stream, stream_size); + } + /* load noOwnerNVWrite */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->noOwnerNVWrite), stream, stream_size); + } + /* load restrictDelegate */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->restrictDelegate), stream, stream_size); + } + /* load tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->tpmDAASeed, stream, stream_size); + } + /* load ownerInstalled */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_permanent_data->ownerInstalled), stream, stream_size); + } + /* load tscOrdinalAuditStatus */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_permanent_data->tscOrdinalAuditStatus), stream, stream_size); + } + /* load allowLoadMaintPub */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_permanent_data->allowLoadMaintPub), stream, stream_size); + } + /* load daaProof */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->daaProof, stream, stream_size); + } + /* load daaBlobKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading DAA Blob key\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->daaBlobKey, stream, stream_size); + } + instanceData = instanceData; /* to quiet the compiler */ + return rc; +} + +/* TPM_PermanentData_Store() serializes the TPM_PERMANENT_DATA structure + + */ + +TPM_RESULT TPM_PermanentData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PermanentData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PERMANENT_DATA); + } + /* store revMajor */ + /* store revMinor */ + /* not stored, loaded from hard coded value */ + /* store tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->tpmProof); + } + /* store EKReset */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->EKReset); + } + /* store ownerAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->ownerAuth); + } + /* store operatorAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->operatorAuth); + } + /* store authDIR */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_permanent_data->authDIR); + } +#ifndef TPM_NOMAINTENANCE + /* mark that manuMaintPub is present */ + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TRUE); + } + /* store manuMaintPub */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_permanent_data->manuMaintPub)); + } +#else + /* mark that manuMaintPub is absent */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, FALSE); + } +#endif + /* store endorsementKey */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, TRUE, &(tpm_permanent_data->endorsementKey)); + } + /* store srk */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, FALSE, &(tpm_permanent_data->srk)); + } + /* store contextKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->contextKey); + } + /* store delegateKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->delegateKey); + } + /* store auditMonotonicCounter */ + if (rc == 0) { + rc = TPM_CounterValue_Store(sbuffer, &(tpm_permanent_data->auditMonotonicCounter)); + } + /* store monotonicCounter */ + if (rc == 0) { + rc = TPM_Counters_Store(sbuffer, tpm_permanent_data->monotonicCounter); + } + /* store pcrAttrib, since they are constants, no need to store to NV space */ + /* store ordinalAuditStatus */ + for (i = 0 ; (rc == 0) && (i < (TPM_ORDINALS_MAX/CHAR_BIT)) ; i++) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_permanent_data->ordinalAuditStatus[i]), sizeof(BYTE)); + } + /* store familyTable */ + if (rc == 0) { + rc = TPM_FamilyTable_Store(sbuffer, + &(tpm_permanent_data->familyTable), + FALSE); /* don't store the tag, to save NV space */ + } + /* store delegateTable */ + if (rc == 0) { + rc = TPM_DelegateTable_Store(sbuffer, &(tpm_permanent_data->delegateTable)); + } + /* store lastFamilyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->lastFamilyID); + } + /* store noOwnerNVWrite */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->noOwnerNVWrite); + } + /* store restrictDelegate */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->restrictDelegate); + } + /* store tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->tpmDAASeed); + } + /* store ownerInstalled */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->ownerInstalled), sizeof(BYTE)); + } + /* store tscOrdinalAuditStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->tscOrdinalAuditStatus), + sizeof(BYTE)); + } + /* store allowLoadMaintPub */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->allowLoadMaintPub), sizeof(BYTE)); + } + /* store daaProof */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->daaProof); + } + /* store daaBlobKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->daaBlobKey); + } + instanceData = instanceData; /* to quiet the compiler */ + return rc; +} + +/* TPM_PermanentData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PermanentData_Zero to zero secrets that are not Delete'd + The object itself is not freed +*/ + +void TPM_PermanentData_Delete(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + printf(" TPM_PermanentData_Delete:\n"); + if (tpm_permanent_data != NULL) { +#ifndef TPM_NOMAINTENANCE + TPM_Pubkey_Delete(&(tpm_permanent_data->manuMaintPub)); +#endif + TPM_Key_Delete(&(tpm_permanent_data->endorsementKey)); + TPM_Key_Delete(&(tpm_permanent_data->srk)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->contextKey)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->delegateKey)); + TPM_FamilyTable_Delete(&(tpm_permanent_data->familyTable)); + TPM_DelegateTable_Delete(&(tpm_permanent_data->delegateTable)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->daaBlobKey)); + /* zero all secrets */ + TPM_PermanentData_Zero(tpm_permanent_data, instanceData); + } + return; +} + +/* TPM_PermanentData_Zero() zeros all secrets not already zeroed and freed by + TPM_PermanentData_Delete() + + It is called by TPM_PermanentData_Delete() and TPM_PermanentData_Init(). It does a subset of + TPM_PermanentData_Init() that will never fail. +*/ + +void TPM_PermanentData_Zero(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + printf(" TPM_PermanentData_Zero:\n"); + instanceData = instanceData; + if (tpm_permanent_data != NULL) { + TPM_Secret_Init(tpm_permanent_data->tpmProof); + TPM_Nonce_Init(tpm_permanent_data->EKReset); + TPM_Secret_Init(tpm_permanent_data->ownerAuth); + TPM_Secret_Init(tpm_permanent_data->operatorAuth); + TPM_Digest_Init(tpm_permanent_data->authDIR); + /* endorsementKey handled by TPM_Key_Delete() */ + /* srk handled by TPM_Key_Delete() */ + /* contextKey handled by TPM_SymmetricKeyData_Free() */ + /* delegateKey handled by TPM_SymmetricKeyData_Free() */ + TPM_Nonce_Init(tpm_permanent_data->tpmDAASeed); + TPM_Nonce_Init(tpm_permanent_data->daaProof); + /* daaBlobKey handled by TPM_SymmetricKeyData_Free() */ + } + return; +} + +/* TPM_PermanentData_InitDaa() generates new values for the 3 DAA elements: tpmDAASeed, daaProof, + and daaBlobKey. + + This is common code, use when creating the EK, revoke trust, and the set capability + used by the owner to invalidate DAA blobs. +*/ + +TPM_RESULT TPM_PermanentData_InitDaa(TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentData_InitDaa:\n"); + /* generate tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_permanent_data->tpmDAASeed); + } + /* generate daaProof*/ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_permanent_data->daaProof); + } + /* generate daaBlobKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_GenerateKey(tpm_permanent_data->daaBlobKey); + } + return rc; +} + +/* + PermanentAll is TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined space. +*/ + +/* TPM_PermanentAll_Load() deserializes all TPM NV data from a stream created by + TPM_PermanentAll_Store(). + + The two functions must be kept in sync. + + Data includes TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, Owner Evict keys, and NV defined space. +*/ + +TPM_RESULT TPM_PermanentAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_PermanentAll_Load:\n"); + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NVSTATE_V1, stream, stream_size); + } + /* TPM_PERMANENT_DATA deserialize from stream */ + if (rc == 0) { + rc = TPM_PermanentData_Load(&(tpm_state->tpm_permanent_data), + stream, stream_size, TRUE); + } + /* TPM_PERMANENT_FLAGS deserialize from stream */ + if (rc == 0) { + rc = TPM_PermanentFlags_Load(&(tpm_state->tpm_permanent_flags), + stream, stream_size); + } + /* owner evict keys deserialize from stream */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictLoad(tpm_state->tpm_key_handle_entries, + stream, stream_size); + } + /* NV defined space deserialize from stream */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Load(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_PermanentAll_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_PermanentAll_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_PermanentAll_Store() serializes all TPM NV data into a stream that can be restored through + TPM_PermanentAll_Load(). + + The two functions must be kept in sync. + + Data includes TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, Owner Evict keys, and NV defined space. + + The TPM_STORE_BUFFER, buffer and length are returned for convenience. + + This has two uses: + + - It is called before the actual NV store to serialize the data + - It is called by TPM_NV_DefineSpace to determine if there is enough NV space for the new index +*/ + +TPM_RESULT TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer, /* freed by caller */ + const unsigned char **buffer, + uint32_t *length, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_DIGEST tpm_digest; + + printf(" TPM_PermanentAll_Store:\n"); + /* overall format tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_V1); + } + /* serialize TPM_PERMANENT_DATA */ + if (rc == 0) { + rc = TPM_PermanentData_Store(sbuffer, + &(tpm_state->tpm_permanent_data), TRUE); + } + /* serialize TPM_PERMANENT_FLAGS */ + if (rc == 0) { + rc = TPM_PermanentFlags_Store(sbuffer, + &(tpm_state->tpm_permanent_flags)); + } + /* serialize owner evict keys */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictStore(sbuffer, + tpm_state->tpm_key_handle_entries); + } + /* serialize NV defined space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Store(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, buffer, length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + *length, *buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_PermanentAll_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + /* get the final serialized buffer and its length */ + if (rc == 0) { + TPM_Sbuffer_Get(sbuffer, buffer, length); + } + return rc; +} + +/* TPM_PermanentAll_NVLoad() + + Deserialize the TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined + space from a stream read from the NV file TPM_PERMANENT_ALL_NAME. + + Returns: + + 0 success + TPM_RETRY if file does not exist (first time) + TPM_FAIL on failure to load (fatal), since they should never occur +*/ + +TPM_RESULT TPM_PermanentAll_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_PermanentAll_NVLoad:\n"); + if (rc == 0) { + /* try loading from NVRAM */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_PERMANENT_ALL_NAME); + } + /* deserialize from stream */ + if (rc == 0) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_PermanentAll_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_PermanentAll_NVLoad: Error (fatal) loading deserializing NV state\n"); + rc = TPM_FAIL; + } + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_PermanentAll_NVStore() serializes all NV data and stores it in the NV file + TPM_PERMANENT_ALL_NAME + + If the writeAllNV flag is FALSE, the function is a no-op, and returns the input 'rcIn'. + + If writeAllNV is TRUE and rcIn is not TPM_SUCCESS, this indicates that the ordinal + modified the in-memory TPM_PERMANENT_DATA and/or TPM_PERMANENT_FLAGS structures (perhaps only + partially) and then detected an error. Since the command is failing, roll back the structure by + reading the NV file. If the read then fails, this is a fatal error. + + Similarly, if writeAllNV is TRUE and the actual NV write fails, this is a fatal error. +*/ + +TPM_RESULT TPM_PermanentAll_NVStore(tpm_state_t *tpm_state, + TPM_BOOL writeAllNV, + TPM_RESULT rcIn) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + TPM_NV_DATA_ST *tpm_nv_data_st = NULL; /* array of saved NV index volatile flags */ + + printf(" TPM_PermanentAll_NVStore: write flag %u\n", writeAllNV); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (writeAllNV) { + if (rcIn == TPM_SUCCESS) { + /* serialize state to be written to NV */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + /* validate the length of the stream against the maximum provided NV space */ + if (rc == 0) { + printf(" TPM_PermanentAll_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_NV_SPACE) { + printf("TPM_PermanentAll_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_NV_SPACE); + rc = TPM_NOSPACE; + } + } + /* store the buffer in NVRAM */ + if (rc == 0) { + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_PERMANENT_ALL_NAME); + } + if (rc != 0) { + printf("TPM_PermanentAll_NVStore: Error (fatal), " + "NV structure in-memory caches are in invalid state\n"); + rc = TPM_FAIL; + } + } + else { + /* An in-memory structure was altered, but the ordinal had a subsequent error. Since + the structure is in an invalid state, roll back to the previous value by reading the + NV file. */ + printf(" TPM_PermanentAll_NVStore: Ordinal error, " + "rolling back NV structure cache\n"); + /* Save a copy of the NV defined space volatile state. It is not stored in NV, so it + will be destroyed during the rollback. */ + /* get a copy of the NV volatile flags, to be used during a rollback */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetVolatile(&tpm_nv_data_st, /* freed @2 */ + &(tpm_state->tpm_nv_index_entries)); + } + /* Returns TPM_RETRY on non-existent file */ + if (rc == 0) { + printf(" TPM_PermanentAllNVStore: Deleting TPM_PERMANENT_DATA structure\n"); + TPM_PermanentData_Delete(&(tpm_state->tpm_permanent_data), TRUE); + printf(" TPM_PermanentAllNVStore: Deleting owner evict keys\n"); + TPM_KeyHandleEntries_OwnerEvictDelete(tpm_state->tpm_key_handle_entries); + printf(" TPM_PermanentAllNVStore: Deleting NV defined space \n"); + TPM_NVIndexEntries_Delete(&(tpm_state->tpm_nv_index_entries)); + printf(" TPM_PermanentAllNVStore: " + "Rereading TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys\n"); + /* re-allocate TPM_PERMANENT_DATA data structures */ + rc = TPM_PermanentData_Init(&(tpm_state->tpm_permanent_data), TRUE); + } + if (rc == 0) { + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + if (rc == 0) { + rc = TPM_NVIndexEntries_SetVolatile(tpm_nv_data_st, + &(tpm_state->tpm_nv_index_entries)); + } + /* after a successful rollback, return the ordinal's original error code */ + if (rc == 0) { + rc = rcIn; + } + /* a failure during rollback is fatal */ + else { + printf("TPM_PermanentAll_NVStore: Error (fatal), " + "Permanent Data, Flags, or owner evict keys structure is invalid\n"); + rc = TPM_FAIL; + } + + } + } + /* no write required, no-op */ + else { + rc = rcIn; + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + free(tpm_nv_data_st); /* @2 */ + return rc; +} + +/* TPM_PermanentAll_NVDelete() deletes ann NV data in the NV file TPM_PERMANENT_ALL_NAME. + + If mustExist is TRUE, returns an error if the file does not exist. + + It does not delete the in-memory copy. +*/ + +TPM_RESULT TPM_PermanentAll_NVDelete(uint32_t tpm_number, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentAll_NVDelete:\n"); + /* remove the NVRAM file */ + if (rc == 0) { + rc = TPM_NVRAM_DeleteName(tpm_number, + TPM_PERMANENT_ALL_NAME, + mustExist); + } + return rc; +} + +/* TPM_PermanentAll_IsSpace() determines if there is enough NV space for the serialized NV state. + + It does this by serializing the entire state and comparing the length to the configured maximum. +*/ + +TPM_RESULT TPM_PermanentAll_IsSpace(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf("TPM_PermanentAll_IsSpace :\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + if (rc == 0) { + printf(" TPM_PermanentAll_IsSpace: Require %u bytes\n", length); + if (length > TPM_MAX_NV_SPACE) { + printf("TPM_PermanentAll_IsSpace: No space, need %u max %u\n", + length, TPM_MAX_NV_SPACE); + rc = TPM_NOSPACE; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_PermanentAll_GetSpace() returns the NV free space. + + It does this by serializing the entire state and comparing the length to the configured maximum. +*/ + +TPM_RESULT TPM_PermanentAll_GetSpace(uint32_t *bytes_free, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_NVRAM_IsSpace:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + if (rc == 0) { + printf(" TPM_PermanentAll_GetSpace: Used %u max %u bytes\n", length, TPM_MAX_NV_SPACE); + if (length > TPM_MAX_NV_SPACE) { + /* This should never occur */ + printf("TPM_PermanentAll_GetSpace: Error (fatal) Used more than maximum\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + *bytes_free = TPM_MAX_NV_SPACE - length; + printf(" TPM_PermanentAll_GetSpace: Free space %u\n", *bytes_free); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + diff --git a/src/tpm12/tpm_permanent.h b/src/tpm12/tpm_permanent.h new file mode 100644 index 0000000..2d95acb --- /dev/null +++ b/src/tpm12/tpm_permanent.h @@ -0,0 +1,108 @@ +/********************************************************************************/ +/* */ +/* Permanent Flag and Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_permanent.h 4623 2011-09-28 15:15:09Z 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. */ +/********************************************************************************/ + +#ifndef TPM_PERMANENT_H +#define TPM_PERMANENT_H + +#include "tpm_global.h" +#include "tpm_structures.h" + + +/* + TPM_PERMANENT_FLAGS +*/ + +void TPM_PermanentFlags_Init(TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_Load(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PermanentFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_LoadBitmap(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + TPM_TAG permanentFlagsVersion, + uint32_t tpm_bitmap); +TPM_RESULT TPM_PermanentFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_StoreBytes(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); + +/* + TPM_PERMANENT_DATA +*/ + +TPM_RESULT TPM_PermanentData_Init(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +TPM_RESULT TPM_PermanentData_Load(TPM_PERMANENT_DATA *tpm_permanent_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL instanceData); +TPM_RESULT TPM_PermanentData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +void TPM_PermanentData_Delete(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +void TPM_PermanentData_Zero(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); + +TPM_RESULT TPM_PermanentData_InitDaa(TPM_PERMANENT_DATA *tpm_permanent_data); + +/* + PermanentAll is TPM_PERMANENT_DATA plus TPM_PERMANENT_FLAGS +*/ + +TPM_RESULT TPM_PermanentAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_PermanentAll_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_PermanentAll_NVStore(tpm_state_t *tpm_state, + TPM_BOOL writeAllNV, + TPM_RESULT rcIn); +TPM_RESULT TPM_PermanentAll_NVDelete(uint32_t tpm_number, + TPM_BOOL mustExist); + +TPM_RESULT TPM_PermanentAll_IsSpace(tpm_state_t *tpm_state); +TPM_RESULT TPM_PermanentAll_GetSpace(uint32_t *bytes_free, + tpm_state_t *tpm_state); + +#endif diff --git a/src/tpm12/tpm_platform.c b/src/tpm12/tpm_platform.c new file mode 100644 index 0000000..16da5db --- /dev/null +++ b/src/tpm12/tpm_platform.c @@ -0,0 +1,175 @@ +/********************************************************************************/ +/* */ +/* TPM Platform I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_platform.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "tpm_debug.h" +#include "tpm_pcr.h" +#include "tpm_platform.h" + +#ifdef TPM_LIBTPMS_CALLBACKS +#include "tpm_library_intern.h" +#endif + +#ifndef TPM_IO_LOCALITY + +/* TPM_IO_GetLocality() is platform specific code to set the localityModifier before an ordinal is + processed. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GetLocality(TPM_MODIFIER_INDICATOR *localityModifier, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_io_getlocality) { + rc = cbs->tpm_io_getlocality(localityModifier, tpm_number); + return rc; + } +#else + tpm_number = tpm_number; /* to silence the compiler */ +#endif + + if (rc == 0) { + *localityModifier = 0; + printf(" TPM_IO_GetLocality: localityModifier %u\n", *localityModifier); + rc = TPM_LocalityModifier_CheckLegal(*localityModifier); + } + return rc; +} + +#endif /* TPM_IO_LOCALITY */ + +#ifndef TPM_IO_PHYSICAL_PRESENCE + +/* TPM_IO_GetPhysicalPresence() is platform specific code to get the hardware physicalPresence + state. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GetPhysicalPresence(TPM_BOOL *physicalPresence, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_io_getphysicalpresence) { + rc = cbs->tpm_io_getphysicalpresence(physicalPresence, tpm_number); + return rc; + } +#else + tpm_number = tpm_number; /* to silence the compiler */ +#endif + *physicalPresence = FALSE; + return rc; +} + +#endif /* TPM_IO_PHYSICAL_PRESENCE */ + +#ifndef TPM_IO_GPIO + +/* TPM_IO_GPIO_Write() should write 'dataSize' bytes of 'data' to 'nvIndex' at the GPIO port. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GPIO_Write(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + tpm_number = tpm_number; /* to silence the compiler */ + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + printf(" TPM_IO_GPIO_Write: nvIndex %08x\n", nvIndex); + TPM_PrintAll(" TPM_IO_GPIO_Write: Stub", data, dataSize); + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + nvIndex = nvIndex; /* unused parameter, to quiet the compiler */ + dataSize = dataSize; + data = data; + printf("TPM_IO_GPIO_Write: Error (fatal), platform does not support GPIO\n"); + rc = TPM_FAIL; /* Should never get here. The invalid address be detected earlier */ +#endif + return rc; +} + +/* TPM_IO_GPIO_Read() + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GPIO_Read(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + tpm_number = tpm_number; /* to silence the compiler */ + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + printf(" TPM_IO_GPIO_Read: nvIndex %08x\n", nvIndex); + memset(data, 0, dataSize); + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + nvIndex = nvIndex;; /* unused parameter, to quiet the compiler */ + dataSize = dataSize;; + data = data; + printf("TPM_IO_GPIO_Read: Error (fatal), platform does not support GPIO\n"); + rc = TPM_FAIL; /* Should never get here. The invalid address be detected earlier */ +#endif + return rc; +} + +#endif /* TPM_IO_GPIO */ + diff --git a/src/tpm12/tpm_platform.h b/src/tpm12/tpm_platform.h new file mode 100644 index 0000000..94036e0 --- /dev/null +++ b/src/tpm12/tpm_platform.h @@ -0,0 +1,64 @@ +/********************************************************************************/ +/* */ +/* TPM Platform I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_platform.h 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +/* Interface independent platform I/O Functions */ + +#ifndef TPM_PLATFORM_H +#define TPM_PLATFORM_H + +#include "tpm_types.h" + +/* Every platform will need this function, as TPM_MainInit() calls it. */ + +TPM_RESULT TPM_IO_Init(void); + +TPM_RESULT TPM_IO_GetLocality(TPM_MODIFIER_INDICATOR *localityModifier, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GetPhysicalPresence(TPM_BOOL *physicalPresence, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GPIO_Write(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GPIO_Read(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number); + +#endif diff --git a/src/tpm12/tpm_process.c b/src/tpm12/tpm_process.c new file mode 100644 index 0000000..02c2f49 --- /dev/null +++ b/src/tpm12/tpm_process.c @@ -0,0 +1,6051 @@ +/********************************************************************************/ +/* */ +/* TPM Command Processor */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_process.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifdef TPM_POSIX +#include <sys/types.h> +#include <unistd.h> +#endif + +#include "tpm_admin.h" +#include "tpm_audit.h" +#include "tpm_auth.h" +#include "tpm_constants.h" +#include "tpm_commands.h" +#include "tpm_counter.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_error.h" +#include "tpm_identity.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_maint.h" +#include "tpm_memory.h" +#include "tpm_migration.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_owner.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_session.h" +#include "tpm_sizedbuffer.h" +#include "tpm_startup.h" +#include "tpm_storage.h" +#include "tpm_ticks.h" +#include "tpm_transport.h" +#include "tpm_ver.h" + +#include "tpm_process.h" + +/* local prototypes */ + +/* get capabilities */ + +static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse, + uint32_t ordinal); +static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID); +static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse, + uint16_t protocolID); +static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capFlag); +static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capProperty); +static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse); +static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + TPM_SIZED_BUFFER *subCap); +static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse, + TPM_SYM_MODE symMode); +static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t tpm_key_handle); +static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *subCap); +static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t nvIndex); +static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID); +static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_RESOURCE_TYPE resourceType); +static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse, + TPM_ENC_SCHEME encScheme); +static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID); +static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap); +#if (TPM_REVISION >= 103) /* added for rev 103 */ +static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap, + tpm_state_t *tpm_state); +#endif +static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse, + TPM_PERMANENT_DATA *tpm_permanent_data); + +static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse); +static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse); + +/* set capabilities */ + +static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32); +static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32); +static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue); +static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue); + +/* + TPM_CAP_VERSION_INFO +*/ + +/* TPM_CapVersionInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CapVersionInfo_Init(TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + printf(" TPM_CapVersionInfo_Init:\n"); + TPM_Version_Init(&(tpm_cap_version_info->version)); + tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL; + tpm_cap_version_info->errataRev = TPM_ERRATA_REV; + memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID, + sizeof(tpm_cap_version_info->tpmVendorID)); + tpm_cap_version_info->vendorSpecificSize = 0; + tpm_cap_version_info->vendorSpecific = NULL; + return; +} + +/* TPM_CapVersionInfo_Set() sets members to software specific data */ + +void TPM_CapVersionInfo_Set(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + printf(" TPM_CapVersionInfo_Set:\n"); + TPM_Version_Set(&(tpm_cap_version_info->version), tpm_permanent_data); + tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL; + tpm_cap_version_info->errataRev = TPM_ERRATA_REV; + memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID, + sizeof(tpm_cap_version_info->tpmVendorID)); + tpm_cap_version_info->vendorSpecificSize = 0; + tpm_cap_version_info->vendorSpecific = NULL; + return; +} + +#if 0 /* not required */ +/* TPM_CapVersionInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CapVersionInfo_Init() or TPM_CapVersionInfo_Set() + After use, call TPM_CapVersionInfo_Delete() to free memory +*/ + +TPM_RESULT TPM_CapVersionInfo_Load(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CapVersionInfo_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CAP_VERSION_INFO, stream, stream_size); + } + /* load version */ + if (rc == 0) { + rc = TPM_Version_Load(&(tpm_cap_version_info->version), stream, stream_size); + } + /* load specLevel */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_cap_version_info->specLevel), stream, stream_size); + } + /* load errataRev */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_cap_version_info->errataRev), sizeof(tpm_cap_version_info->errataRev), + stream, stream_size); + } + /* load tpmVendorID */ + if (rc == 0) { + rc = TPM_Loadn(tpm_cap_version_info->tpmVendorID, sizeof(tpm_cap_version_info->tpmVendorID), + stream, stream_size); + } + /* load vendorSpecificSize */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_cap_version_info->vendorSpecificSize), stream, stream_size); + } + /* allocate memory for vendorSpecific */ + if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) { + rc = TPM_Malloc(&(tpm_cap_version_info->vendorSpecific), + tpm_cap_version_info->vendorSpecificSize); + } + /* load vendorSpecific */ + if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) { + rc = TPM_Loadn(tpm_cap_version_info->vendorSpecific, + tpm_cap_version_info->vendorSpecificSize, + stream, stream_size); + } + return rc; +} +#endif + +/* TPM_CapVersionInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CapVersionInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CapVersionInfo_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CAP_VERSION_INFO); + } + /* store version */ + if (rc == 0) { + rc = TPM_Version_Store(sbuffer, &(tpm_cap_version_info->version)); + } + /* store specLevel */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->specLevel); + } + /* store errataRev */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_cap_version_info->errataRev), + sizeof(tpm_cap_version_info->errataRev)); + } + /* store tpmVendorID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_cap_version_info->tpmVendorID, + sizeof(tpm_cap_version_info->tpmVendorID)); + } + /* store vendorSpecificSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->vendorSpecificSize); + } + /* store vendorSpecific */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_cap_version_info->vendorSpecific, + tpm_cap_version_info->vendorSpecificSize); + } + return rc; +} + +/* TPM_CapVersionInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CapVersionInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CapVersionInfo_Delete(TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + printf(" TPM_CapVersionInfo_Delete:\n"); + if (tpm_cap_version_info != NULL) { + free(tpm_cap_version_info->vendorSpecific); + TPM_CapVersionInfo_Init(tpm_cap_version_info); + } + return; +} + +/* + Processing Commands +*/ + + +/* 17. Ordinals rev 107 + + This structure maps the specification Ordinals table to software functions and parameters. + + It provides direct mapping that easier to understand and maintain than scattering and hard coding + these values. + + The functions currently supported are: + + - processing jump table for 1.1 and 1.2 (implied get capability - ordinals supported) + - allow audit + - audit default value + - owner delegation permissions + - key delegation permissions + - wrappable + + Future possibilities include: + + - no owner, disabled, deactivated + - 0,1,2 auth + + typedef struct tdTPM_ORDINAL_TABLE { + + TPM_COMMAND_CODE ordinal; + tpm_process_function_t process_function_v11; + tpm_process_function_t process_function_v12; + TPM_BOOL auditable; + TPM_BOOL auditDefault; + uint16_t ownerPermissionBlock; + uint32_t ownerPermissionPosition; + uint16_t keyPermissionBlock; + uint32_t keyPermissionPosition; + uint32_t inputHandleSize; + uint32_t keyHandles; + uint32_t outputHandleSize; + TPM_BOOL transportWrappable; + TPM_BOOL instanceWrappable; + TPM_BOOL hardwareWrappable; + } TPM_ORDINAL_TABLE; +*/ + +static TPM_ORDINAL_TABLE tpm_ordinal_table[] = +{ + {TPM_ORD_ActivateIdentity, + TPM_Process_ActivateIdentity, TPM_Process_ActivateIdentity, + TRUE, + TRUE, + 1, TPM_DELEGATE_ActivateIdentity, + 1, TPM_KEY_DELEGATE_ActivateIdentity, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_AuthorizeMigrationKey, + TPM_Process_AuthorizeMigrationKey, TPM_Process_AuthorizeMigrationKey, + TRUE, + TRUE, + 1, TPM_DELEGATE_AuthorizeMigrationKey, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifyKey, + TPM_Process_CertifyKey, TPM_Process_CertifyKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CertifyKey, + sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE), + 2, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifyKey2, + TPM_Process_Unused, TPM_Process_CertifyKey2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CertifyKey2, + sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE), + 2, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifySelfTest, + TPM_Process_CertifySelfTest, TPM_Process_Unused, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuth, + TPM_Process_ChangeAuth, TPM_Process_ChangeAuth, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuth, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthAsymFinish, + TPM_Process_ChangeAuthAsymFinish, TPM_Process_ChangeAuthAsymFinish, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuthAsymFinish, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthAsymStart, + TPM_Process_ChangeAuthAsymStart, TPM_Process_ChangeAuthAsymStart, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuthAsymStart, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthOwner, + TPM_Process_ChangeAuthOwner, TPM_Process_ChangeAuthOwner, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_ApproveMA, + TPM_Process_Unused, TPM_Process_CMK_ApproveMA, + TRUE, + FALSE, + 1, TPM_DELEGATE_CMK_ApproveMA, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_ConvertMigration, + TPM_Process_Unused, TPM_Process_CMK_ConvertMigration, + TRUE, + FALSE, + 1, TPM_KEY_DELEGATE_CMK_ConvertMigration, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateBlob, + TPM_Process_Unused, TPM_Process_CMK_CreateBlob, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CMK_CreateBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateKey, + TPM_Process_Unused, TPM_Process_CMK_CreateKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CMK_CreateKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateTicket, + TPM_Process_Unused, TPM_Process_CMK_CreateTicket, + TRUE, + FALSE, + 1, TPM_DELEGATE_CMK_CreateTicket, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_SetRestrictions, + TPM_Process_Unused, TPM_Process_CMK_SetRestrictions, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ContinueSelfTest, + TPM_Process_ContinueSelfTest, TPM_Process_ContinueSelfTest, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ConvertMigrationBlob, + TPM_Process_ConvertMigrationBlob, TPM_Process_ConvertMigrationBlob, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_ConvertMigrationBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateCounter, + TPM_Process_Unused, TPM_Process_CreateCounter, + TRUE, + FALSE, + 1, TPM_DELEGATE_CreateCounter, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateEndorsementKeyPair, + TPM_Process_CreateEndorsementKeyPair, TPM_Process_CreateEndorsementKeyPair, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_CreateMaintenanceArchive, +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_CreateMaintenanceArchive, TPM_Process_CreateMaintenanceArchive, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_CreateMaintenanceArchive, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateMigrationBlob, + TPM_Process_CreateMigrationBlob, TPM_Process_CreateMigrationBlob, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_CreateMigrationBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateRevocableEK, + TPM_Process_Unused, TPM_Process_CreateRevocableEK, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateWrapKey, + TPM_Process_CreateWrapKey, TPM_Process_CreateWrapKey, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_CreateWrapKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DAA_Join, + TPM_Process_Unused, TPM_Process_DAAJoin, + TRUE, + FALSE, + 1, TPM_DELEGATE_DAA_Join, + 0, 0, + sizeof(TPM_HANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DAA_Sign, + TPM_Process_Unused, TPM_Process_DAASign, + TRUE, + FALSE, + 1, TPM_DELEGATE_DAA_Sign, + 0, 0, + sizeof(TPM_HANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_CreateKeyDelegation, + TPM_Process_Unused, TPM_Process_DelegateCreateKeyDelegation, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_CreateOwnerDelegation, + TPM_Process_Unused, TPM_Process_DelegateCreateOwnerDelegation, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_CreateOwnerDelegation, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_LoadOwnerDelegation, + TPM_Process_Unused, TPM_Process_DelegateLoadOwnerDelegation, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_LoadOwnerDelegation, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_Manage, + TPM_Process_Unused, TPM_Process_DelegateManage, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_Manage, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_ReadTable, + TPM_Process_Unused, TPM_Process_DelegateReadTable, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_UpdateVerification, + TPM_Process_Unused, TPM_Process_DelegateUpdateVerification, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_UpdateVerification, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_VerifyDelegation, + TPM_Process_Unused, TPM_Process_DelegateVerifyDelegation, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DirRead, + TPM_Process_DirRead, TPM_Process_DirRead, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DirWriteAuth, + TPM_Process_DirWriteAuth, TPM_Process_DirWriteAuth, + TRUE, + FALSE, + 1, TPM_DELEGATE_DirWriteAuth, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisableForceClear, + TPM_Process_DisableForceClear, TPM_Process_DisableForceClear, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisableOwnerClear, + TPM_Process_DisableOwnerClear, TPM_Process_DisableOwnerClear, + TRUE, + TRUE, + 1, TPM_DELEGATE_DisableOwnerClear, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisablePubekRead, + TPM_Process_DisablePubekRead, TPM_Process_DisablePubekRead, + TRUE, + TRUE, + 1, TPM_DELEGATE_DisablePubekRead, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DSAP, + TPM_Process_Unused, TPM_Process_DSAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_ENTITY_TYPE) + sizeof(TPM_KEY_HANDLE) + TPM_NONCE_SIZE + sizeof(uint32_t), + 0xffffffff, + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_EstablishTransport, + TPM_Process_Unused, TPM_Process_EstablishTransport, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_EstablishTransport, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_EvictKey, + TPM_Process_EvictKey, TPM_Process_EvictKey, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ExecuteTransport, + TPM_Process_Unused, TPM_Process_ExecuteTransport, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_Extend, + TPM_Process_Extend, TPM_Process_Extend, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_FieldUpgrade, + TPM_Process_Unused, TPM_Process_Unused, + TRUE, + FALSE, + 1, TPM_DELEGATE_FieldUpgrade, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_FlushSpecific, + TPM_Process_Unused, TPM_Process_FlushSpecific, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0xffffffff, + 0, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_ForceClear, + TPM_Process_ForceClear, TPM_Process_ForceClear, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditDigest, + TPM_Process_Unused, TPM_Process_GetAuditDigest, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditDigestSigned, + TPM_Process_Unused, TPM_Process_GetAuditDigestSigned, + FALSE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_GetAuditDigestSigned, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditEvent, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditEventSigned, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetCapability, + TPM_Process_GetCapability, TPM_Process_GetCapability, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_GetCapabilityOwner, + TPM_Process_GetCapabilityOwner, TPM_Process_GetCapabilityOwner, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetCapabilitySigned, + TPM_Process_GetCapabilitySigned, TPM_Process_Unused, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetOrdinalAuditStatus, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetPubKey, + TPM_Process_GetPubKey, TPM_Process_GetPubKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_GetPubKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetRandom, + TPM_Process_GetRandom, TPM_Process_GetRandom, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetTestResult, + TPM_Process_GetTestResult, TPM_Process_GetTestResult, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetTicks, + TPM_Process_Unused, TPM_Process_GetTicks, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_IncrementCounter, + TPM_Process_Unused, TPM_Process_IncrementCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Init, + TPM_Process_Init, TPM_Process_Init, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_KeyControlOwner, + TPM_Process_Unused, TPM_Process_KeyControlOwner, + TRUE, + FALSE, + 1, TPM_DELEGATE_KeyControlOwner, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_KillMaintenanceFeature, +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_KillMaintenanceFeature, TPM_Process_KillMaintenanceFeature, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_KillMaintenanceFeature, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadAuthContext, + TPM_Process_LoadAuthContext, TPM_Process_LoadAuthContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadContext, + TPM_Process_Unused, TPM_Process_LoadContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0, + sizeof(TPM_HANDLE), + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_LoadKey, + TPM_Process_LoadKey, TPM_Process_LoadKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_LoadKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadKey2, + TPM_Process_Unused, TPM_Process_LoadKey2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_LoadKey2, + sizeof(TPM_KEY_HANDLE), + 1, + sizeof(TPM_KEY_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadKeyContext, + TPM_Process_LoadKeyContext, TPM_Process_LoadKeyContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_KEY_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadMaintenanceArchive, +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_LoadMaintenanceArchive, TPM_Process_LoadMaintenanceArchive, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_LoadMaintenanceArchive, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadManuMaintPub, +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_LoadManuMaintPub, TPM_Process_LoadManuMaintPub, + TRUE, + TRUE, +#endif + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_MakeIdentity, + TPM_Process_MakeIdentity, TPM_Process_MakeIdentity, + TRUE, + TRUE, + 1, TPM_DELEGATE_MakeIdentity, + 1, TPM_KEY_DELEGATE_MakeIdentity, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_MigrateKey, + TPM_Process_Unused, TPM_Process_MigrateKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_MigrateKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_DefineSpace, + TPM_Process_Unused, TPM_Process_NVDefineSpace, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_DefineSpace, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_ReadValue, + TPM_Process_Unused, TPM_Process_NVReadValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_ReadValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_ReadValueAuth, + TPM_Process_Unused, TPM_Process_NVReadValueAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_WriteValue, + TPM_Process_Unused, TPM_Process_NVWriteValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_WriteValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_WriteValueAuth, + TPM_Process_Unused, TPM_Process_NVWriteValueAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OIAP, + TPM_Process_OIAP, TPM_Process_OIAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_OSAP, + TPM_Process_OSAP, TPM_Process_OSAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_ENTITY_TYPE) + sizeof(uint32_t) + TPM_NONCE_SIZE, + 0, /* TPM_OSAP: no input or output parameters are encrypted or logged */ + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_OwnerClear, + TPM_Process_OwnerClear, TPM_Process_OwnerClear, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerClear, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerReadInternalPub, + TPM_Process_Unused, TPM_Process_OwnerReadInternalPub, + TRUE, + FALSE, + 1, TPM_DELEGATE_OwnerReadInternalPub, + 0, 0, + 0, + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerReadPubek, + TPM_Process_OwnerReadPubek, TPM_Process_OwnerReadPubek, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerReadPubek, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerSetDisable, + TPM_Process_OwnerSetDisable, TPM_Process_OwnerSetDisable, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerSetDisable, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PCR_Reset, + TPM_Process_Unused, TPM_Process_PcrReset, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PcrRead, + TPM_Process_PcrRead, TPM_Process_PcrRead, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PhysicalDisable, + TPM_Process_PhysicalDisable, TPM_Process_PhysicalDisable, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PhysicalEnable, + TPM_Process_PhysicalEnable, TPM_Process_PhysicalEnable, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_PhysicalSetDeactivated, + TPM_Process_PhysicalSetDeactivated, TPM_Process_PhysicalSetDeactivated, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_Quote, + TPM_Process_Quote, TPM_Process_Quote, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Quote, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + TRUE}, + + {TPM_ORD_Quote2, + TPM_Process_Unused, TPM_Process_Quote2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Quote2, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + TRUE}, + + {TPM_ORD_ReadCounter, + TPM_Process_Unused, TPM_Process_ReadCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReadManuMaintPub, +#if defined(TPM_NOMAINTENANCE) || defined(TPM_NOMAINTENANCE_COMMANDS) + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_ReadManuMaintPub, TPM_Process_ReadManuMaintPub, + TRUE, + TRUE, +#endif + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReadPubek, + TPM_Process_ReadPubek, TPM_Process_ReadPubek, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseCounter, + TPM_Process_Unused, TPM_Process_ReleaseCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseCounterOwner, + TPM_Process_Unused, TPM_Process_ReleaseCounterOwner, + TRUE, + FALSE, + 1, TPM_DELEGATE_ReleaseCounterOwner, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseTransportSigned, + TPM_Process_Unused, TPM_Process_ReleaseTransportSigned, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ReleaseTransportSigned, + 0, + 0, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_Reset, + TPM_Process_Reset, TPM_Process_Reset, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ResetLockValue, + TPM_Process_Unused, TPM_Process_ResetLockValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_ResetLockValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_RevokeTrust, + TPM_Process_Unused, TPM_Process_RevokeTrust, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveAuthContext, + TPM_Process_SaveAuthContext, TPM_Process_SaveAuthContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_AUTHHANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveContext, + TPM_Process_Unused, TPM_Process_SaveContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0xffffffff, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_SaveKeyContext, + TPM_Process_SaveKeyContext, TPM_Process_SaveKeyContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveState, + TPM_Process_SaveState, TPM_Process_SaveState, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_Seal, + TPM_Process_Seal, TPM_Process_Seal, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Seal, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Sealx, + TPM_Process_Unused, TPM_Process_Sealx, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Sealx, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SelfTestFull, + TPM_Process_SelfTestFull, TPM_Process_SelfTestFull, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetCapability, + TPM_Process_Unused, TPM_Process_SetCapability, + TRUE, + FALSE, + 1, TPM_DELEGATE_SetCapability, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_SetOperatorAuth, + TPM_Process_Unused, TPM_Process_SetOperatorAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOrdinalAuditStatus, + TPM_Process_SetOrdinalAuditStatus, TPM_Process_SetOrdinalAuditStatus, + TRUE, + TRUE, + 1, TPM_DELEGATE_SetOrdinalAuditStatus, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOwnerInstall, + TPM_Process_SetOwnerInstall, TPM_Process_SetOwnerInstall, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOwnerPointer, + TPM_Process_Unused, TPM_Process_SetOwnerPointer, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetRedirection, + TPM_Process_Unused, TPM_Process_Unused, + TRUE, + FALSE, + 1, TPM_DELEGATE_SetRedirection, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetTempDeactivated, + TPM_Process_SetTempDeactivated, TPM_Process_SetTempDeactivated, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Complete, + TPM_Process_SHA1Complete, TPM_Process_SHA1Complete, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1CompleteExtend, + TPM_Process_SHA1CompleteExtend, TPM_Process_SHA1CompleteExtend, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Start, + TPM_Process_SHA1Start, TPM_Process_SHA1Start, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Update, + TPM_Process_SHA1Update, TPM_Process_SHA1Update, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Sign, + TPM_Process_Sign, TPM_Process_Sign, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Sign, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Startup, + TPM_Process_Startup, TPM_Process_Startup, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_StirRandom, + TPM_Process_StirRandom, TPM_Process_StirRandom, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_TakeOwnership, + TPM_Process_TakeOwnership, TPM_Process_TakeOwnership, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Terminate_Handle, + TPM_Process_TerminateHandle, TPM_Process_TerminateHandle, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_AUTHHANDLE), + 0, + 0, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_TickStampBlob, + TPM_Process_Unused, TPM_Process_TickStampBlob, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_TickStampBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_UnBind, + TPM_Process_UnBind, TPM_Process_UnBind, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_UnBind, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Unseal, + TPM_Process_Unseal, TPM_Process_Unseal, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Unseal, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TSC_ORD_PhysicalPresence, + TPM_Process_PhysicalPresence, TPM_Process_PhysicalPresence, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TSC_ORD_ResetEstablishmentBit, + TPM_Process_Unused, TPM_Process_ResetEstablishmentBit, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE} + + + +}; + +/* + Ordinal Table Utilities +*/ + +/* TPM_OrdinalTable_GetEntry() gets the table entry for the ordinal. + + If the ordinal is not in the table, TPM_BAD_ORDINAL is returned +*/ + +TPM_RESULT TPM_OrdinalTable_GetEntry(TPM_ORDINAL_TABLE **entry, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = TPM_BAD_ORDINAL; + size_t i; + + /* printf(" TPM_OrdinalTable_GetEntry: Ordinal %08x\n", ordinal); */ + *entry = NULL; + for (i = 0 ; i < (sizeof(tpm_ordinal_table)/sizeof(TPM_ORDINAL_TABLE)) ; i++) { + if (ordinalTable[i].ordinal == ordinal) { /* if found */ + *entry = &(ordinalTable[i]); /* return the entry */ + rc = 0; /* return found */ + break; + } + } + return rc; +} + +/* TPM_OrdinalTable_GetProcessFunction() returns the processing function for the ordinal. + + If the ordinal is not in the table, the function TPM_Process_Unused() is returned. +*/ + +void TPM_OrdinalTable_GetProcessFunction(tpm_process_function_t *tpm_process_function, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + printf(" TPM_OrdinalTable_GetProcessFunction: Ordinal %08x\n", ordinal); + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, ordinalTable, ordinal); + } + if (rc == 0) { /* if found */ +#ifdef TPM_V12 + *tpm_process_function = entry->process_function_v12; +#else + *tpm_process_function = entry->process_function_v11; +#endif + } + else { /* if not found, default processing function */ + *tpm_process_function = TPM_Process_Unused; + } + return; +} + +/* TPM_OrdinalTable_GetAuditable() determines whether the ordinal can ever be audited. + + Used by TPM_Process_SetOrdinalAuditStatus() +*/ + +void TPM_OrdinalTable_GetAuditable(TPM_BOOL *auditable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + printf(" TPM_OrdinalTable_GetAuditable: Ordinal %08x\n", ordinal); + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* if not found, unimplemented, not auditable */ + if (rc != 0) { + *auditable = FALSE; + } + /* if unimplemented, not auditable */ +#ifdef TPM_V12 + else if (entry->process_function_v12 == TPM_Process_Unused) { + *auditable = FALSE; + } +#else + else if (entry->process_function_v11 == TPM_Process_Unused) { + *auditable = FALSE; + } +#endif + /* if found an entry, use it */ + else { + *auditable = entry->auditable; + } + return; +} + +/* TPM_OrdinalTable_GetAuditDefault() determines whether the ordinal is audited by default. + + Used to initialize TPM_PERMANENT_DATA -> ordinalAuditStatus + + Returns FALSE if the ordinal is not in the ordinals table. +*/ + +void TPM_OrdinalTable_GetAuditDefault(TPM_BOOL *auditDefault, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* if not found, unimplemented, not auditable */ + if (rc != 0) { + *auditDefault = FALSE; + } + /* found an entry, return it */ + else { + *auditDefault = entry->auditDefault; + } + return; +} + + +/* TPM_OrdinalTable_GetOwnerPermission() gets the owner permission block and the position within the + block for a permission bit based on the ordinal +*/ + +TPM_RESULT TPM_OrdinalTable_GetOwnerPermission(uint16_t *ownerPermissionBlock, + uint32_t *ownerPermissionPosition, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + if (rc == 0) { + *ownerPermissionBlock = entry->ownerPermissionBlock; + *ownerPermissionPosition = entry->ownerPermissionPosition; + /* sanity check ordinal table entry value */ + if (*ownerPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_OrdinalTable_GetOwnerPermission: Error (fatal): " + "ownerPermissionPosition out of range %u\n", *ownerPermissionPosition); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_OrdinalTable_GetKeyPermission() gets the key permission block and the position within the + block for a permission bit based on the ordinal +*/ + +TPM_RESULT TPM_OrdinalTable_GetKeyPermission(uint16_t *keyPermissionBlock, + uint32_t *keyPermissionPosition, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + if (rc == 0) { + *keyPermissionBlock = entry->keyPermissionBlock; + *keyPermissionPosition = entry->keyPermissionPosition; + if (*keyPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_OrdinalTable_GetKeyPermission: Error (fatal): " + "keyPermissionPosition out of range %u\n", *keyPermissionPosition); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_OrdinalTable_ParseWrappedCmd() parses a transport wrapped command, extracting + + - index into DATAw + - length of DATAw + - number of key handles and their indexes + - ordinal + - transportWrappable FALSE if the command cannot be wrapped in a transport session + + FIXME if audit has to occur before command parsing, this command becomes more generally useful, + and might do the auditing and return the inParamDigest as well. + + This function cannot get the actual key handle(s) because the value may be encrypted, and the + decryption has not occurred yet. +*/ + +TPM_RESULT TPM_OrdinalTable_ParseWrappedCmd(uint32_t *datawStart, + uint32_t *datawLen, + uint32_t *keyHandles, + uint32_t *keyHandle1Index, + uint32_t *keyHandle2Index, + TPM_COMMAND_CODE *ordinal, + TPM_BOOL *transportWrappable, + TPM_SIZED_BUFFER *wrappedCmd) +{ + TPM_RESULT rc = 0; + uint32_t stream_size; + unsigned char *stream; + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_ORDINAL_TABLE *entry; /* table entry for the ordinal */ + uint32_t authLen; /* length of below the line parameters */ + + printf(" TPM_OrdinalTable_ParseWrappedCmd:\n"); + /* Extract the standard command parameters from the command stream. This also validates + paramSize against wrappedCmdSize */ + if (rc == 0) { + /* make temporary copies so the wrappedCmd is not touched */ + /* FIXME might want to return paramSize and tag and move the wrappedCmd pointers */ + stream = wrappedCmd->buffer; + stream_size = wrappedCmd->size; + /* parse the three standard input parameters, check paramSize against wrappedCmd->size */ + rc = TPM_Process_GetCommandParams(&tag, ¶mSize, ordinal, + &stream, &stream_size); + } + /* get the entry from the ordinal table */ + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedCmd: ordinal %08x\n", *ordinal); + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, *ordinal); + } + if (rc == 0) { + /* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */ + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) + + entry->inputHandleSize; + /* authLen is the length of the below-the-line auth parameters that are excluded from the + dataW area */ + switch (tag) { + case TPM_TAG_RQU_AUTH1_COMMAND: + authLen = sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE; + break; + case TPM_TAG_RQU_AUTH2_COMMAND: + authLen = 2 * + (sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE); + break; + case TPM_TAG_RQU_COMMAND: + /* if the tag is illegal, assume the dataW area goes to the end of the command */ + default: + authLen = 0; + break; + } + if (paramSize < *datawStart + authLen) { + printf("TPM_OrdinalTable_ParseWrappedCmd: Error, " + "paramSize %u less than datawStart %u + authLen %u\n", + paramSize, *datawStart, authLen); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + /* subtract safe, cannot be negative after above check */ + *datawLen = paramSize - *datawStart - authLen; + printf(" TPM_OrdinalTable_ParseWrappedCmd: datawStart %u datawLen %u\n", + *datawStart, *datawLen); + /* determine whether the command can be wrapped in a transport session */ + *transportWrappable = entry->transportWrappable; + /* return the number of key handles */ + *keyHandles = entry->keyHandles; + } + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedCmd: key handles %u\n", *keyHandles); + switch (*keyHandles) { + case 0: + /* no key handles */ + break; + case 1: + /* one key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + break; + case 2: + /* first key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + /* second key handle */ + *keyHandle2Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) + + sizeof(TPM_KEY_HANDLE); + break; + case 0xffffffff: + printf(" TPM_OrdinalTable_ParseWrappedCmd: key handles special case\n"); + /* potential key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + /* can't determine handle type here since resourceType is encrypted */ + break; + default: + /* sanity check ordinal table */ + printf("TPM_OrdinalTable_ParseWrappedCmd: Error (fatal), " + "invalid key handles for %08x for ordinal %08x\n", *keyHandles, *ordinal); + rc = TPM_FAIL; /* should never occur */ + break; + } + } + return rc; +} + +/* TPM_OrdinalTable_ParseWrappedRsp() parses a transport wrapped response, extracting + + - index into DATAw + - length of DATAw + - return code RCw + + FIXME this command might do the auditing and return the outParamDigest as well. +*/ + +TPM_RESULT TPM_OrdinalTable_ParseWrappedRsp(uint32_t *datawStart, + uint32_t *datawLen, + TPM_RESULT *rcw, + TPM_COMMAND_CODE ordinal, + const unsigned char *wrappedRspStream, + uint32_t wrappedRspStreamSize) +{ + TPM_RESULT rc = 0; + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_ORDINAL_TABLE *entry; /* table entry for the ordinal */ + uint32_t authLen; /* length of below the line parameters */ + + printf(" TPM_OrdinalTable_ParseWrappedRsp: ordinal %08x\n", ordinal); + /* Extract the standard response parameters from the response stream. This also validates + paramSize against wrappedRspSize */ + if (rc == 0) { + rc = TPM_Process_GetResponseParams(&tag, ¶mSize, rcw, + (unsigned char **)&wrappedRspStream, + &wrappedRspStreamSize); + } + /* get the entry from the ordinal table */ + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedRsp: returnCode %08x\n", *rcw); + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* parse the success return code case */ + if ((rc == 0) && (*rcw == TPM_SUCCESS)) { + if (rc == 0) { + /* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */ + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT) + + entry->outputHandleSize; + /* authLen is the length of the below-the-line auth parameters that are excluded from + the dataW area */ + switch (tag) { + case TPM_TAG_RSP_AUTH1_COMMAND: + authLen = TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE; + break; + case TPM_TAG_RSP_AUTH2_COMMAND: + authLen = 2 * (TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE); + break; + case TPM_TAG_RSP_COMMAND: + /* if the tag is illegal, assume the dataW area goes to the end of the response */ + default: + authLen = 0; + break; + } + if (paramSize < *datawStart + authLen) { + printf("TPM_OrdinalTable_ParseWrappedRsp: Error, " + "paramSize %u less than datawStart %u + authLen %u\n", + paramSize, *datawStart, authLen); + rc = TPM_BAD_PARAM_SIZE; /* FIXME not clear what to do here */ + } + } + if (rc == 0) { + /* subtract safe, cannot be negative after about check */ + *datawLen = paramSize - *datawStart - authLen; + printf(" TPM_OrdinalTable_ParseWrappedRsp: datawStart %u datawLen %u\n", + *datawStart, *datawLen); + } + } + /* if the wrapped command failed, datawStart is not used, and datawLen is 0 */ + else if ((rc == 0) && (*rcw != TPM_SUCCESS)) { + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT); + *datawLen = 0; + printf(" TPM_OrdinalTable_ParseWrappedRsp: datawLen %u\n", *datawLen); + } + return rc; +} + +void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + for (i = 0 ; (i < 4) && (i < TPM_KEY_HANDLES) ; i++) { + printf("TPM_KeyHandleEntries_Trace: %lu handle %08x tpm_key %p\n", + (unsigned long)i, tpm_key_handle_entries[i].handle, tpm_key_handle_entries[i].key); + } + return; +} + +void TPM_State_Trace(tpm_state_t *tpm_state); + +void TPM_State_Trace(tpm_state_t *tpm_state) +{ + printf("TPM_State_Trace: disable %u p_deactive %u v_deactive %u owned %u state %u\n", + tpm_state->tpm_permanent_flags.disable, + tpm_state->tpm_permanent_flags.deactivated, + tpm_state->tpm_stclear_flags.deactivated, + tpm_state->tpm_permanent_data.ownerInstalled, + tpm_state->testState); + return; +} + +/* TPM_ProcessA() is an alternate to TPM_Process() that uses standard C types. It provides an entry + point to the TPM without requiring the TPM_STORE_BUFFER class. + + The design pattern for the response is: + + - set '*response' to NULL at the first call + + - on subsequent calls, pass 'response' and 'response_total' back in. Set 'response_size' back + to 0. + + On input: + + '*response' - pointer to a buffer that was allocated (can be NULL) + + 'response_size' - the number of valid bytes in buffer (ignored if buffer is NULL, can be 0, + cannot be greater than total. Set to zero, unless one wants the TPM_Process() function to append + a response to some existing data. + + '*response_total' - the total number of allocated bytes (ignored if buffer is NULL) + + On output: + + '*response' - pointer to a buffer that was allocated or reallocated + + 'response_size' - the number of valid bytes in buffer + + '*response_total' - the total number of allocated or reallocated bytes +*/ + +TPM_RESULT TPM_ProcessA(unsigned char **response, + uint32_t *response_size, + uint32_t *response_total, + unsigned char *command, /* complete command array */ + uint32_t command_size) /* actual bytes in command */ + +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER responseSbuffer; + + /* set the sbuffer from the response parameters */ + if (rc == 0) { + rc = TPM_Sbuffer_Set(&responseSbuffer, + *response, + *response_size, + *response_total); + } + if (rc == 0) { + rc = TPM_Process(&responseSbuffer, + command, /* complete command array */ + command_size); /* actual bytes in command */ + + } + /* get the response parameters from the sbuffer */ + if (rc == 0) { + TPM_Sbuffer_GetAll(&responseSbuffer, + response, + response_size, + response_total); + } + return rc; +} + +/* Process the command from the host to the TPM. + + 'command_size' is the actual size of the command stream. + + Returns: + 0 on success + + non-zero on a fatal error preventing the command from being processed. The response is + invalid in this case. +*/ + +TPM_RESULT TPM_Process(TPM_STORE_BUFFER *response, + unsigned char *command, /* complete command array */ + uint32_t command_size) /* actual bytes in command */ +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* fatal error in ordinal processing, + can be returned */ + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_COMMAND_CODE ordinal = 0; + tpm_process_function_t tpm_process_function = NULL; /* based on ordinal */ + tpm_state_t *targetInstance = NULL; /* TPM global state */ + TPM_STORE_BUFFER localBuffer; /* for response if instance was not found */ + TPM_STORE_BUFFER *sbuffer; /* either localBuffer or the instance response + buffer */ + + TPM_Sbuffer_Init(&localBuffer); /* freed @1 */ + /* get the global TPM state */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + targetInstance = tpm_instances[0]; + } + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* clear the response form the previous ordinal, the response buffer is reused */ + TPM_Sbuffer_Clear(&(targetInstance->tpm_stclear_data.ordinalResponse)); + /* extract the standard command parameters from the command stream */ + returnCode = TPM_Process_GetCommandParams(&tag, ¶mSize, &ordinal, + &command, &command_size); + } + /* preprocessing common to all ordinals */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_Preprocess(targetInstance, ordinal, NULL); + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries); + } + /* process the ordinal */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* get the processing function from the ordinal table */ + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* call the processing function to execute the command */ + returnCode = tpm_process_function(targetInstance, + &(targetInstance->tpm_stclear_data.ordinalResponse), + tag, command_size, ordinal, command, + NULL); /* not from encrypted transport */ + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries); + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_State_Trace(targetInstance); + } +#ifdef TPM_VOLATILE_STORE + /* save the volatile state after each command to handle fail-over restart */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_VolatileAll_NVStore(targetInstance); + } +#endif /* TPM_VOLATILE_STORE */ + /* If the ordinal processing function returned without a fatal error, append its ordinalResponse + to the output response buffer */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Sbuffer_AppendSBuffer(response, + &(targetInstance->tpm_stclear_data.ordinalResponse)); + } + if ((rc == 0) && (returnCode != TPM_SUCCESS)) { + /* gets here if: + + - there was an error before the ordinal was processed + - the ordinal returned a fatal error + - an error occurred appending the ordinal response + + returnCode should be the response + errors here are fatal, can't create an error response + */ + /* if it failed after the target instance was found, use the instance's response buffer */ + if (targetInstance != NULL) { + sbuffer = &(targetInstance->tpm_stclear_data.ordinalResponse); + } + /* if it failed before even the target instance was found, use a local buffer */ + else { + sbuffer = &localBuffer; + } + if (rc == 0) { + /* it's not even known whether the initial response was stored, so just start + over */ + TPM_Sbuffer_Clear(sbuffer); + /* store the tag, paramSize, and returnCode */ + printf("TPM_Process: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rc = TPM_Sbuffer_StoreInitialResponse(sbuffer, TPM_TAG_RQU_COMMAND, returnCode); + } + /* call this to handle the TPM_FAIL causing the TPM going into failure mode */ + if (rc == 0) { + rc = TPM_Sbuffer_StoreFinalResponse(sbuffer, returnCode, targetInstance); + } + if (rc == 0) { + rc = TPM_Sbuffer_AppendSBuffer(response, sbuffer); + } + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&localBuffer); /* @1 */ + return rc; +} + +/* TPM_Process_Wrapped() is called recursively to process a wrapped command. + + 'command_size' is the actual size of the command stream. + + 'targetInstance' is an input indicating the TPM instance being called. + + 'transportInternal' not NULL indicates that this function was called recursively from + TPM_ExecuteTransport + + For wrapped commands, this function cannot trust that command_size and the incoming paramSize in + the command stream are consistent. Therefore, this function checks for consistency. + + The processor ensures that the response bytes are set according to the outgoing paramSize on + return. + + Returns: + 0 on success + + non-zero on a fatal error preventing the command from being processed. The response is + invalid in this case. +*/ + +TPM_RESULT TPM_Process_Wrapped(TPM_STORE_BUFFER *response, + unsigned char *command, /* complete command array */ + uint32_t command_size, /* actual bytes in command */ + tpm_state_t *targetInstance, /* global TPM state */ + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* non-fatal error, returned in response */ + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_COMMAND_CODE ordinal = 0; + tpm_process_function_t tpm_process_function = NULL; /* based on ordinal */ + TPM_STORE_BUFFER ordinalResponse; /* response for this ordinal */ + + printf("TPM_Process_Wrapped:\n"); + TPM_Sbuffer_Init(&ordinalResponse); /* freed @1 */ + /* Set the tag, paramSize, and ordinal from the wrapped command stream */ + /* If paramSize does not equal the command stream size, return TPM_BAD_PARAM_SIZE */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_GetCommandParams(&tag, ¶mSize, &ordinal, + &command, &command_size); + } + /* preprocessing common to all ordinals */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_Preprocess(targetInstance, ordinal, transportInternal); + } + /* process the ordinal */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* get the processing function from the ordinal table */ + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* call the processing function to execute the command */ + returnCode = tpm_process_function(targetInstance, &ordinalResponse, + tag, command_size, ordinal, command, + transportInternal); + } + /* If the ordinal processing function returned without a fatal error, append its ordinalResponse + to the output response buffer */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Sbuffer_AppendSBuffer(response, &ordinalResponse); + } + /* If: + + - an error in this function occurred before the ordinal was processed + - the ordinal processing function returned a fatal error + - an error occurred appending the ordinal response + + then use the return code of that failure as the final response. Failure here is fatal, since + no error code can be returned. + */ + if ((rc == 0) && (returnCode != TPM_SUCCESS)) { + rc = TPM_Sbuffer_StoreFinalResponse(response, returnCode, targetInstance); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&ordinalResponse); /* @1 */ + return rc; +} + +/* TPM_Process_GetCommandParams() gets the standard 3 parameters from the command input stream + + The stream is adjusted to point past the parameters. + + The resulting paramSize is checked against the stream size for consistency. paramSize is + returned for reference, but command_size reflects the remaining bytes in the stream. +*/ + +TPM_RESULT TPM_Process_GetCommandParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_COMMAND_CODE *ordinal, + unsigned char **command, + uint32_t *command_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Process_GetCommandParams:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(tag, command, command_size); + } + /* get paramSize */ + if (rc == 0) { + rc = TPM_Load32(paramSize, command, command_size); + } + /* get ordinal */ + if (rc == 0) { + rc = TPM_Load32(ordinal, command, command_size); + } + /* check the paramSize against the command_size */ + if (rc == 0) { + if (*paramSize != + *command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)) { + + printf("TPM_Process_GetCommandParams: Error, " + "command size %lu not equal to paramSize %u\n", + (unsigned long) + (*command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)), + *paramSize); + rc = TPM_BAD_PARAM_SIZE; + } + else { + printf(" TPM_Process_GetCommandParams: tag %04x paramSize %u ordinal %08x\n", + *tag, *paramSize, *ordinal); + } + } + return rc; +} + +/* TPM_Process_GetResponseParams() gets the standard 3 parameters from the response output stream + + The stream is adjusted to point past the parameters. + + The resulting paramSize is checked against the stream size for consistency. paramSize is + returned for reference, but response_size reflects the remaining bytes in the stream. +*/ + +TPM_RESULT TPM_Process_GetResponseParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_RESULT *returnCode, + unsigned char **response, + uint32_t *response_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Process_GetResponseParams:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(tag, response, response_size); + } + /* get paramSize */ + if (rc == 0) { + rc = TPM_Load32(paramSize, response, response_size); + } + /* get returnCode */ + if (rc == 0) { + rc = TPM_Load32(returnCode, response, response_size); + } + /* check the paramSize against the response_size */ + if (rc == 0) { + if (*paramSize != (*response_size + sizeof(TPM_TAG) + + sizeof(uint32_t) + sizeof(TPM_RESULT))) { + + printf("TPM_Process_GetResponseParams: Error, " + "response size %lu not equal to paramSize %u\n", + (unsigned long) + (*response_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)), + *paramSize); + rc = TPM_BAD_PARAM_SIZE; + } + else { + printf(" TPM_Process_GetResponseParams: tag %04x paramSize %u ordinal %08x\n", + *tag, *paramSize, *returnCode); + } + } + return rc; +} + +/* TPM_CheckRequestTagnnn() is common code to verify the command tag */ + +TPM_RESULT TPM_CheckRequestTag210(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) && + (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) && + (tpm_tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_CheckRequestTag210: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag21(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) && + (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_CheckRequestTag21: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag2(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) { + printf("TPM_CheckRequestTag2: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag10(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) && + (tpm_tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_CheckRequestTag10: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag1(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) { + printf("TPM_CheckRequestTag1: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag0(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_COMMAND) { + printf("TPM_CheckRequestTag0: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_Process_Unused(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; + + printf("TPM_Process_Unused:\n"); + tpm_state = tpm_state; /* not used */ + paramSize = paramSize; /* not used */ + ordinal = ordinal; /* not used */ + command = command; /* not used */ + transportInternal = transportInternal; /* not used */ + printf("TPM_Process_Unused: Ordinal returnCode %08x %u\n", + TPM_BAD_ORDINAL, TPM_BAD_ORDINAL); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, TPM_BAD_ORDINAL); + return rcf; +} + +/* TPM_CheckState() should be called by all commands. It checks a set of flags specified by + tpm_check_map to determine whether the command can execute in that state. + + Returns: 0 if the command can execute + non-zero error code that should be returned as a response +*/ + +TPM_RESULT TPM_CheckState(tpm_state_t *tpm_state, + TPM_TAG tag, + uint32_t tpm_check_map) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CheckState: Check map %08x\n", tpm_check_map); + /* check the dictionary attack lockout, only for authorized commands */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_NO_LOCKOUT) && (tag != TPM_TAG_RQU_COMMAND)) { + rc = TPM_Authdata_CheckState(tpm_state); + } + } + /* TPM_GetTestResult. This command can assist the TPM manufacturer in determining the cause of + the self-test failure. iii. All other operations will return the error code + TPM_FAILEDSELFTEST. */ + if (rc == 0) { + if (tpm_check_map & TPM_CHECK_NOT_SHUTDOWN) { + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + printf("TPM_CheckState: Error, shutdown is TRUE\n"); + rc = TPM_FAILEDSELFTEST; + } + } + } + /* TPM_Startup SHALL execute as normal, and is the only function that does not call + TPM_CheckState(). All other commands SHALL return TPM_INVALID_POSTINIT */ + if (rc == 0) { + if (tpm_state->tpm_stany_flags.postInitialise) { + printf("TPM_CheckState: Error, postInitialise is TRUE\n"); + rc = TPM_INVALID_POSTINIT; + } + } + /* + For checking disabled and deactivated, the check is NOT done if it's one of the special NV + commands (indicated by TPM_CHECK_NV_NOAUTH) and nvLocked is FALSE, indicating that the NV + store does not require authorization + */ + /* For commands available only when enabled. */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_ENABLED) && + !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_CheckState: Error, disable is TRUE\n"); + rc = TPM_DISABLED; + } + } + } + /* For commands only available when activated. */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_ACTIVATED) && + !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_CheckState: Error, deactivated is TRUE\n"); + rc = TPM_DEACTIVATED; + } + } + } + /* For commands available only after an owner is installed. see Ordinals chart */ + if (rc == 0) { + if (tpm_check_map & TPM_CHECK_OWNER) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_CheckState: Error, ownerInstalled is FALSE\n"); + rc = TPM_NOSRK; + } + } + } + return rc; +} + +/* TPM_Process_Preprocess() handles check functions common to all ordinals + + 'transportPublic' not NULL indicates that this function was called recursively from + TPM_ExecuteTransport +*/ + +TPM_RESULT TPM_Process_Preprocess(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + + printf(" TPM_Process_Preprocess: Ordinal %08x\n", ordinal); + /* Preprocess to check if command can be run in limited operation mode */ + if (rc == 0) { + if (tpm_state->testState == TPM_TEST_STATE_LIMITED) { + /* 1. At startup, a TPM MUST self-test all internal functions that are necessary to do + TPM_SHA1Start, TPM_SHA1Update, TPM_SHA1Complete, TPM_SHA1CompleteExtend, TPM_Extend, + TPM_Startup, TPM_ContinueSelfTest, a subset of TPM_GetCapability, and + TPM_GetTestResult.. + */ + if (!((ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_SHA1Start) || + (ordinal == TPM_ORD_SHA1Update) || + (ordinal == TPM_ORD_SHA1Complete) || + (ordinal == TPM_ORD_SHA1CompleteExtend) || + (ordinal == TPM_ORD_Extend) || + (ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_ContinueSelfTest) || + /* a subset of TPM_GetCapability does not require self-test. The ordinal itself + decides whether to run TPM_ContinueSelfTest() */ + (ordinal == TPM_ORD_GetCapability) || + /* 3. The TPM MAY allow TPM_SelfTestFull to be used before completion of the + actions of TPM_ContinueSelfTest. */ + (ordinal == TPM_ORD_SelfTestFull) || + (ordinal == TPM_ORD_GetTestResult) || + /* 2. The TSC_PhysicalPresence and TSC_ResetEstablishmentBit commands do not + operate on shielded-locations and have no requirement to be self-tested before + any use. TPM's SHOULD test these functions before operation. */ + (ordinal == TSC_ORD_PhysicalPresence) || + (ordinal == TSC_ORD_ResetEstablishmentBit) + )) { + /* One of the optional actions. */ + /* rc = TPM_NEEDS_SELFTEST; */ + /* Alternatively, could run the actions of continue self-test */ + rc = TPM_ContinueSelfTestCmd(tpm_state); + } + } + } + /* special pre-processing for SHA1 context */ + if (rc == 0) { + rc = TPM_Check_SHA1Context(tpm_state, ordinal, transportInternal); + } + /* Special pre-processing to invalidate the saved state if it exists. Omit this processing for + TPM_Startup, since that function might restore the state first */ + if (rc == 0) { + if (tpm_state->tpm_stany_flags.stateSaved && + !((ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_Init))) { + /* For any other ordinal, invalidate the saved state if it exists. */ + rc = TPM_SaveState_NVDelete(tpm_state, TRUE); + } + } + /* When an exclusive session is running, execution of any command other then + TPM_ExecuteTransport or TPM_ReleaseTransportSigned targeting the exclusive session causes the + abnormal invalidation of the exclusive transport session. */ + if ((rc == 0) && (transportInternal == NULL)) { /* do test only for the outer ordinal */ + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && /* active exclusive */ + /* These two ordinals terminate the exclusive transport session if the transport handle + is not the specified handle. So the check is deferred until the command is parsed + for the transport handle. */ + !((ordinal == TPM_ORD_ExecuteTransport) || + (ordinal == TPM_ORD_ReleaseTransportSigned))) { + rc = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* call platform specific code to set the localityModifier */ + if ((rc == 0) && (transportInternal == NULL)) { /* do only for the outer ordinal */ + rc = TPM_IO_GetLocality(&(tpm_state->tpm_stany_flags.localityModifier), + tpm_state->tpm_number); + } + return rc; +} + + +/* TPM_Check_SHA1Context() checks the current SHA1 context + + The TPM may not allow any other types of processing during the execution of a SHA-1 + session. There is only one SHA-1 session active on a TPM. After the execution of SHA1Start, and + prior to SHA1End, the receipt of any command other than SHA1Update will cause the invalidation of + the SHA-1 session. + + 2. After receipt of TPM_SHA1Start, and prior to the receipt of TPM_SHA1Complete or + TPM_SHA1CompleteExtend, receipt of any command other than TPM_SHA1Update invalidates the SHA-1 + session. + + a. If the command received is TPM_ExecuteTransport, the SHA-1 session invalidation is based on + the wrapped command, not the TPM_ExecuteTransport ordinal. + + b. A SHA-1 thread (start, update, complete) MUST take place either completely outside a transport + session or completely within a single transport session. +*/ + +TPM_RESULT TPM_Check_SHA1Context(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; + + if ((tpm_state->sha1_context != NULL) && /* if there was a SHA-1 context set up */ + (ordinal != TPM_ORD_ExecuteTransport)) /* depends on the wrapped command */ + { + /* the non-SHA1 ordinals invalidate the SHA-1 session */ + if ( + ((ordinal != TPM_ORD_SHA1Update) && + (ordinal != TPM_ORD_SHA1Complete) && + (ordinal != TPM_ORD_SHA1CompleteExtend)) || + + /* invalidate if the SHA1 ordinal is within a transport session and the session was not + set up within the same transport session. */ + ((transportInternal != NULL) && + (tpm_state->transportHandle != transportInternal->transHandle)) || + + /* invalidate if the SHA1 ordinal is not within a transport session and the session was + set up with a transport session */ + ((transportInternal == NULL) && + (tpm_state->transportHandle != 0)) + + ) { + + printf("TPM_Check_SHA1Context: Invalidating SHA1 context\n"); + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + return rc; +} + +/* TPM_GetInParamDigest() does common processing of input parameters. + + Common processing includes: + + - determining if the ordinal is being run within an encrypted transport session, since the + inParamDigest does not have to be calculated for audit in that case. + + - retrieving the audit status. It is determinant of whether the input parameter digest should be + calculated. + + - calculating the input parameter digest for HMAC authorization and/or auditing + + This function is called before authorization for several reasons. + + 1 - It makes ordinal processing code more uniform, since authorization sometimes occurs far into + the actions. + + 2 - It is a minor optimization, since the resulting inParamDigest can be used twice in an auth-2 + command, as well as extending the audit digest. +*/ + +TPM_RESULT TPM_GetInParamDigest(TPM_DIGEST inParamDigest, /* output */ + TPM_BOOL *auditStatus, /* output */ + TPM_BOOL *transportEncrypt, /* output */ + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + unsigned char *inParamStart, + unsigned char *inParamEnd, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* this function return code */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + + printf(" TPM_GetInParamDigest:\n"); + if (rc == 0) { + /* TRUE if called from encrypted transport session. This is currently only needed when + auditing, but it's safer to always initialize it */ + *transportEncrypt = + (transportInternal != NULL) && + (transportInternal->transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT); + printf(" TPM_GetInParamDigest: transportEncrypt %02x\n", *transportEncrypt); + /* Determine if the ordinal should be audited. */ + rc = TPM_OrdinalAuditStatus_GetAuditStatus(auditStatus, + ordinal, + &(tpm_state->tpm_permanent_data)); + } + /* If inParamDigest is needed for: + + 1 - for auditing (auditStatus == TRUE) and not called from an encrypted transport. Different + parameters are audited if the ordinal is called through an encrypted transport session. + + 2 - for authorization (tag != auth-0) + */ + if (rc == 0) { + if ((*auditStatus && !(*transportEncrypt)) || /* digest for auditing */ + (tag != TPM_TAG_RQU_COMMAND)) { /* digest for authorization */ + + /* convert ordinal to network byte order */ + nOrdinal = htonl(ordinal); + + /* a. Create inParamDigest - digest of inputs above the double line. NOTE: If there + are no inputs other than the ordinal, inParamEnd - inParamStart will be 0, + terminating the SHA1 vararg hash. It is important that the termination condition + be the length and not the NULL pointer. */ + rc = TPM_SHA1(inParamDigest, + sizeof(TPM_COMMAND_CODE), &nOrdinal, /* 1S */ + inParamEnd - inParamStart, inParamStart, /* 2S - ... */ + 0, NULL); + if (rc == 0) { + TPM_PrintFour(" TPM_GetInParamDigest: inParamDigest", inParamDigest); + } + } + } + return rc; +} + +/* TPM_GetOutParamDigest() does common processing of output parameters. + + It calculates the output parameter digest for HMAC generation and/or auditing if required. +*/ + +TPM_RESULT TPM_GetOutParamDigest(TPM_DIGEST outParamDigest, /* output */ + TPM_BOOL auditStatus, /* input audit status */ + TPM_BOOL transportEncrypt, /* wrapped in encrypt transport */ + TPM_TAG tag, + TPM_RESULT returnCode, + TPM_COMMAND_CODE ordinal, /* command ordinal (hbo) */ + unsigned char *outParamStart, /* starting point of param's */ + uint32_t outParamLength) /* length of param's */ +{ + TPM_RESULT rc = 0; + TPM_RESULT nreturnCode; /* returnCode in nbo */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + + printf(" TPM_GetOutParamDigest:\n"); + if (rc == 0) { + if ((auditStatus && !transportEncrypt) || (tag != TPM_TAG_RQU_COMMAND)) { + nreturnCode = htonl(returnCode); + nOrdinal = htonl(ordinal); + /* a. Create outParamDigest - digest of outputs above the double line. NOTE: If there + are no outputs other than the returnCode and ordinal, outParamLength + will be 0, terminating the SHA1 vararg hash. It is important that the termination + condition be the length and not the NULL pointer. */ + rc = TPM_SHA1(outParamDigest, + sizeof(TPM_RESULT), &nreturnCode, /* 1S */ + sizeof(TPM_COMMAND_CODE), &nOrdinal, /* 2S */ + outParamLength, outParamStart, /* 3S - ...*/ + 0, NULL); + if (rc == 0) { + TPM_PrintFour(" TPM_GetOutParamDigest: outParamDigest", outParamDigest); + } + } + } + return rc; +} + +/* TPM_ProcessAudit() rev 109 + + This function is called when command auditing is required. + + This function must be called after the output authorization, since it requires the (almost) final + return code. +*/ + +TPM_RESULT TPM_ProcessAudit(tpm_state_t *tpm_state, + TPM_BOOL transportEncrypt, /* wrapped in encrypt transport */ + TPM_DIGEST inParamDigest, + TPM_DIGEST outParamDigest, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; /* audit return code */ + TPM_BOOL isZero; + TPM_RESULT nreturnCode; /* returnCode in nbo */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + TPM_DIGEST transportDigest; /* special case digest in encrypted transport */ + + printf(" TPM_ProcessAudit:\n"); + + /* The TPM will execute the ordinal and perform auditing in the following manner: */ + /* 1. Execute command */ + /* a. Execution implies the performance of the listed actions for the ordinal. */ + /* 2. If the command will return TPM_SUCCESS */ + /* a. If TPM_STANY_DATA -> auditDigest is all zeros */ + if (rc == 0) { + TPM_Digest_IsZero(&isZero, tpm_state->tpm_stclear_data.auditDigest); + if (isZero) { + /* i. Increment TPM_PERMANENT_DATA -> auditMonotonicCounter by 1 */ + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter++; + printf(" TPM_ProcessAudit: Incrementing auditMonotonicCounter to %u\n", + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter); + rc = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + /* b. Create A1 a TPM_AUDIT_EVENT_IN structure */ + /* i. Set A1 -> inputParms to the digest of the input parameters from the command */ + /* (1) Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + /* ii. Set A1 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* c. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A1) */ + if (rc == 0) { + /* normal case, audit uses inParamDigest */ + if (!transportEncrypt) { + rc = TPM_AuditDigest_ExtendIn(tpm_state, inParamDigest); + } + /* 1. When the wrapped command requires auditing and the transport session specifies + encryption, the TPM MUST perform the audit. However, when computing the audit digest: + */ + else { + /* a. For input, only the ordinal is audited. */ + if (rc == 0) { + nOrdinal = htonl(ordinal); + rc = TPM_SHA1(transportDigest, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + if (rc == 0) { + rc = TPM_AuditDigest_ExtendIn(tpm_state, transportDigest); + } + } + } + /* d. Create A2 a TPM_AUDIT_EVENT_OUT structure */ + /* i. Set A2 -> outputParms to the digest of the output parameters from the command */ + /* (1). Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + /* ii. Set A2 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* e. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A2) */ + + /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and + the audit occurs before the state is saved. If an error occurs while or after the state is + saved, the audit still occurs. + */ + if ((rc == 0) && (ordinal != TPM_ORD_SaveState)) { + /* normal case, audit uses outParamDigest */ + if (!transportEncrypt) { + rc = TPM_AuditDigest_ExtendOut(tpm_state, outParamDigest); + } + /* 1. When the wrapped command requires auditing and the transport session specifies + encryption, the TPM MUST perform the audit. However, when computing the audit digest: + */ + else { + /* b. For output, only the ordinal and return code are audited. */ + if (rc == 0) { + nreturnCode = htonl(TPM_SUCCESS); /* only called when TPM_SUCCESS */ + nOrdinal = htonl(ordinal); + rc = TPM_SHA1(transportDigest, + sizeof(TPM_RESULT), &nreturnCode, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + if (rc == 0) { + rc = TPM_AuditDigest_ExtendOut(tpm_state, transportDigest); + } + } + } + /* 1. When, in performing the audit process, the TPM has an internal failure (unable to write, + SHA-1 failure etc.) the TPM MUST set the internal TPM state such that the TPM returns the + TPM_FAILEDSELFTEST error on subsequent attempts to execute a command. */ + /* 2. The return code for the command uses the following rules */ + /* a. Command result success, audit success -> return TPM_SUCCESS */ + /* b. Command result failure, no audit -> return command result failure */ + /* c. Command result success, audit failure -> return TPM_AUDITFAIL_SUCCESSFUL */ + /* 3. If the TPM is permanently nonrecoverable after an audit failure, then the TPM MUST always + return TPM_FAILEDSELFTEST for every command other than TPM_GetTestResult. This state must + persist regardless of power cycling, the execution of TPM_Init or any other actions. */ + if (rc != 0) { + rc = TPM_AUDITFAIL_SUCCESSFUL; + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* + Processing Functions +*/ + +/* 7.1 TPM_GetCapability rev 99 + + This command returns current information regarding the TPM. + + The limitation on what can be returned in failure mode restricts the information a manufacturer + may return when capArea indicates TPM_CAP_MFR. +*/ + +TPM_RESULT TPM_Process_GetCapability(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_TAG returnCode = 0; /* command return code */ + + /* input parameters */ + TPM_CAPABILITY_AREA capArea; /* Partition of capabilities to be interrogated */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + + /* 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 = FALSE;/* wrapped in encrypted transport session */ + uint16_t subCap16 = 0; /* the subCap as a uint16_t */ + uint32_t subCap32 = 0; /* the subCap as a uint32_t */ + TPM_STORE_BUFFER capabilityResponse; /* response */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_GetCapability: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_Sbuffer_Init(&capabilityResponse); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapability: capArea %08x\n", capArea); + returnCode = TPM_SizedBuffer_Load(&subCap, &command, ¶mSize); + } + /* subCap is often a uint16_t or uint32_t, create them now */ + if (returnCode == TPM_SUCCESS) { + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + } + /* 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 */ + /* The shutdown test is delayed until after the subcap is calculated */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_NO_LOCKOUT); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapability: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + check state + */ + /* 1. The TPM validates the capArea and subCap indicators. If the information is available, the + TPM creates the response field and fills in the actual information. */ + /* 2. The structure document contains the list of caparea and subCap values */ + if (returnCode == TPM_SUCCESS) { + /* 3. If the TPM is in failure mode or limited operation mode, the TPM MUST return */ + if ((tpm_state->testState == TPM_TEST_STATE_FAILURE) || + (tpm_state->testState == TPM_TEST_STATE_LIMITED)) { + /* a. TPM_CAP_VERSION */ + /* b. TPM_CAP_VERSION_VAL */ + /* c. TPM_CAP_MFR */ + /* d. TPM_CAP_PROPERTY -> TPM_CAP_PROP_MANUFACTURER */ + /* e. TPM_CAP_PROPERTY -> TPM_CAP_PROP_DURATION */ + /* f. TPM_CAP_PROPERTY -> TPM_CAP_PROP_TIS_TIMEOUT */ + /* g. The TPM MAY return any other capability. */ + if ( + !(capArea == TPM_CAP_VERSION) && + !(capArea == TPM_CAP_VERSION_VAL) && + !(capArea == TPM_CAP_MFR) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_MANUFACTURER)) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_DURATION)) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_TIS_TIMEOUT)) + ) { + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + printf("TPM_Process_GetCapability: Error, shutdown capArea %08x subCap %08x\n", + capArea, subCap32); + returnCode = TPM_FAILEDSELFTEST; + } + else { + printf("TPM_Process_GetCapability: Limited operation, run self-test\n"); + returnCode = TPM_ContinueSelfTestCmd(tpm_state); + } + } + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapability: capArea %08x subCap32 subCap16 %08x %04x\n", + capArea, subCap32, subCap16); + returnCode = TPM_GetCapabilityCommon(&capabilityResponse, tpm_state, + capArea, subCap16, subCap32, &subCap); + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_GetCapability: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* store the capabilityResponse */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &capabilityResponse); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&subCap); /* @1 */ + TPM_Sbuffer_Delete(&capabilityResponse); /* @2 */ + return rcf; +} + +/* TPM_GetSubCapInt() converts from a TPM_SIZED_BUFFER to either a uint16_t or uint32_t as + applicable + + No return code is needed. If the size it not applicable, a 0 value is returned, which is + (fortunately) always illegal for subCap integral values. +*/ + +void TPM_GetSubCapInt(uint16_t *subCap16, + uint32_t *subCap32, + TPM_SIZED_BUFFER *subCap) +{ + *subCap16 = 0; /* default, means was not a uint16_t */ + *subCap32 = 0; /* default, means was not a uint32_t */ + if (subCap->size == sizeof(uint32_t)) { + *subCap32 = htonl(*(uint32_t *)subCap->buffer); + printf(" TPM_GetSubCapInt: subCap %08x\n", *subCap32); + } + else if (subCap->size == sizeof(uint16_t)) { + *subCap16 = htons(*(uint16_t *)subCap->buffer); + printf(" TPM_GetSubCapInt: subCap %04x\n", *subCap16); + } +} + + +/* TPM_GetCapabilityCommon() is common code for getting a capability. + + It loads the result to 'capabilityResponse' + + A previously called TPM_GetSubCapInt() converts the subCap buffer into a subCap16 if the size is + 2 or subCap32 if the size is 4. If the values are used, this function checks the size to ensure + that the incoming subCap parameter was correct for the capArea. +*/ + +TPM_RESULT TPM_GetCapabilityCommon(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap) + +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapabilityCommon: capArea %08x\n", capArea); + switch (capArea) { + case TPM_CAP_ORD: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapOrd(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_ALG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapAlg(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_PID: + if (subCap->size == sizeof(uint16_t)) { + rc = TPM_GetCapability_CapPid(capabilityResponse, subCap16); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_FLAG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapFlag(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_PROPERTY: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapProperty(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_VERSION: + rc = TPM_GetCapability_CapVersion(capabilityResponse); + break; + case TPM_CAP_KEY_HANDLE: + /* This is command is available for backwards compatibility. It is the same as + TPM_CAP_HANDLE with a resource type of keys. */ + rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse, + tpm_state->tpm_key_handle_entries); + break; + case TPM_CAP_CHECK_LOADED: + rc = TPM_GetCapability_CapCheckLoaded(capabilityResponse, + tpm_state->tpm_key_handle_entries, + subCap); + break; + case TPM_CAP_SYM_MODE: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapSymMode(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_KEY_STATUS: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapKeyStatus(capabilityResponse, + tpm_state->tpm_key_handle_entries, + subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_NV_LIST: + rc = TPM_NVIndexEntries_GetNVList(capabilityResponse, &(tpm_state->tpm_nv_index_entries)); + break; + case TPM_CAP_MFR: + rc = TPM_GetCapability_CapMfr(capabilityResponse, tpm_state, subCap); + break; + case TPM_CAP_NV_INDEX: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapNVIndex(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_TRANS_ALG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapTransAlg(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_HANDLE: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapHandle(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_TRANS_ES: + if (subCap->size == sizeof(uint16_t)) { + rc = TPM_GetCapability_CapTransEs(capabilityResponse, subCap16); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_AUTH_ENCRYPT: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapAuthEncrypt(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_SELECT_SIZE: + rc = TPM_GetCapability_CapSelectSize(capabilityResponse, subCap); + break; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_CAP_DA_LOGIC: + rc = TPM_GetCapability_CapDaLogic(capabilityResponse, subCap, tpm_state); + break; +#endif + case TPM_CAP_VERSION_VAL: + rc = TPM_GetCapability_CapVersionVal(capabilityResponse, + &(tpm_state->tpm_permanent_data)); + break; + default: + printf("TPM_GetCapabilityCommon: Error, unsupported capArea %08x", capArea); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the ordinal. + + FALSE indicates that the TPM does not support the ordinal. +*/ + +static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse, + uint32_t ordinal) +{ + TPM_RESULT rc = 0; + tpm_process_function_t tpm_process_function; + TPM_BOOL supported; + + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* determine of the ordinal is supported */ + if (tpm_process_function != TPM_Process_Unused) { + supported = TRUE; + } + /* if the processing function is 'Unused', it's not supported */ + else { + supported = FALSE; + } + printf(" TPM_GetCapability_CapOrd: Ordinal %08x, result %02x\n", + ordinal, supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* algorithmID is TPM_ALG_XX: A value from TPM_ALGORITHM_ID + + Boolean value. TRUE means that the TPM supports the asymmetric algorithm for TPM_Sign, TPM_Seal, + TPM_UnSeal and TPM_UnBind and related commands. FALSE indicates that the asymmetric algorithm is + not supported for these types of commands. The TPM MAY return TRUE or FALSE for other than + asymmetric algorithms that it supports. Unassigned and unsupported algorithm IDs return FALSE. +*/ + +static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapAlg: algorithmID %08x\n", algorithmID); + if (algorithmID == TPM_ALG_RSA) { + supported = TRUE; + } + else { + supported = FALSE; + } + printf(" TPM_GetCapability_CapAlg: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the protocol, + + FALSE indicates that the TPM does not support the protocol. +*/ + +static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse, + uint16_t protocolID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapPid: protocolID %04hx\n", protocolID); + switch (protocolID) { + /* supported protocols */ + case TPM_PID_OIAP: + case TPM_PID_OSAP: + case TPM_PID_ADIP: + case TPM_PID_ADCP: + case TPM_PID_DSAP: + case TPM_PID_TRANSPORT: + case TPM_PID_OWNER: + supported = TRUE; + break; + /* unsupported protocols */ + default: + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapPid: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* + Either of the next two subcaps + + TPM_CAP_FLAG_PERMANENT Return the TPM_PERMANENT_FLAGS structure + + TPM_CAP_FLAG_VOLATILE Return the TPM_STCLEAR_FLAGS structure +*/ + +static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capFlag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapFlag: capFlag %08x\n", capFlag); + switch (capFlag) { + case TPM_CAP_FLAG_PERMANENT: + printf(" TPM_GetCapability_CapFlag: TPM_CAP_FLAG_PERMANENT\n");; + rc = TPM_PermanentFlags_StoreBytes(capabilityResponse, &(tpm_state->tpm_permanent_flags)); + break; + case TPM_CAP_FLAG_VOLATILE: + printf(" TPM_GetCapability_CapFlag: TPM_CAP_FLAG_VOLATILE\n"); + rc = TPM_StclearFlags_Store(capabilityResponse, &(tpm_state->tpm_stclear_flags)); + break; + default: + printf("TPM_GetCapability_CapFlag: Error, illegal capFlag %08x\n", capFlag); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* TPM_GetCapability_CapProperty() handles Subcap values for CAP_PROPERTY rev 100 + */ + +static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capProperty) +{ + TPM_RESULT rc = 0; + uint32_t uint32; + uint32_t uint32a; + uint32_t dummy; /* to hold unused response parameter */ + + printf(" TPM_GetCapability_CapProperty: capProperty %08x\n", capProperty); + switch (capProperty) { + case TPM_CAP_PROP_PCR: /* Returns the number of PCR registers supported by the TPM */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_PCR %u\n", TPM_NUM_PCR); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_PCR); + break; + case TPM_CAP_PROP_DIR: /* Returns the number of DIR registers under control of the TPM + owner supported by the TPM. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DIR %u\n", TPM_AUTHDIR_SIZE); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_AUTHDIR_SIZE); + break; + case TPM_CAP_PROP_MANUFACTURER: /* Returns the Identifier of the TPM manufacturer. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MANUFACTURER %.4s\n", + TPM_MANUFACTURER); + rc = TPM_Sbuffer_Append(capabilityResponse, (const unsigned char *)TPM_MANUFACTURER, 4); + break; + case TPM_CAP_PROP_KEYS: /* Returns the number of 2048-bit RSA keys that can be loaded. This + MAY vary with time and circumstances. */ + TPM_KeyHandleEntries_GetSpace(&uint32, tpm_state->tpm_key_handle_entries); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_KEYS %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MIN_COUNTER: /* uint32_t. The minimum amount of time in 10ths of a second + that must pass between invocations of incrementing the + monotonic counter. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MIN_COUNTER\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, 0); + break; + case TPM_CAP_PROP_AUTHSESS: /* The number of available authorization sessions. This MAY + vary with time and circumstances. */ + TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_AUTHSESS space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_TRANSESS: /* The number of available transport sessions. This MAY vary + with time and circumstances. */ + TPM_TransportSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.transSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TRANSESS space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_COUNTERS: /* The number of available monotonic counters. This MAY vary + with time and circumstances. */ + TPM_Counters_GetSpace(&uint32, tpm_state->tpm_permanent_data.monotonicCounter); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_COUNTERS %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_AUTHSESS: /* The maximum number of loaded authorization sessions the + TPM supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_AUTHSESS %u\n", + TPM_MIN_AUTH_SESSIONS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_AUTH_SESSIONS); + break; + case TPM_CAP_PROP_MAX_TRANSESS: /* The maximum number of loaded transport sessions the TPM + supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_TRANSESS %u\n", + TPM_MIN_TRANS_SESSIONS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_TRANS_SESSIONS); + break; + case TPM_CAP_PROP_MAX_COUNTERS: /* The maximum number of monotonic counters under control of + TPM_CreateCounter */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_COUNTERS %u\n", + TPM_MIN_COUNTERS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_COUNTERS); + break; + case TPM_CAP_PROP_MAX_KEYS: /* The maximum number of 2048 RSA keys that the TPM can + support. The number does not include the EK or SRK. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_KEYS %u\n", TPM_KEY_HANDLES); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_KEY_HANDLES); + break; + case TPM_CAP_PROP_OWNER: /* A value of TRUE indicates that the TPM has successfully installed + an owner. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_OWNER %02x\n", + tpm_state->tpm_permanent_data.ownerInstalled); + rc = TPM_Sbuffer_Append(capabilityResponse, + &(tpm_state->tpm_permanent_data.ownerInstalled), sizeof(TPM_BOOL)); + break; + case TPM_CAP_PROP_CONTEXT: /* The number of available saved session slots. This MAY + vary with time and circumstances. */ + TPM_ContextList_GetSpace(&uint32, &dummy, tpm_state->tpm_stclear_data.contextList); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_CONTEXT: /* The maximum number of saved session slots. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_CONTEXT %u\n", + TPM_MIN_SESSION_LIST); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_SESSION_LIST); + break; + case TPM_CAP_PROP_FAMILYROWS: /* The number of rows in the family table */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_FAMILYROWS %u\n", + TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + break; + case TPM_CAP_PROP_TIS_TIMEOUT: + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TIS_TIMEOUT\n"); + rc = TPM_GetCapability_CapPropTisTimeout(capabilityResponse); + break; + case TPM_CAP_PROP_STARTUP_EFFECT: /* The TPM_STARTUP_EFFECTS structure */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_STARTUP_EFFECT %08x\n", + TPM_STARTUP_EFFECTS_VALUE); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_STARTUP_EFFECTS_VALUE); + break; + case TPM_CAP_PROP_DELEGATE_ROW: /* The size of the delegate table in rows. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DELEGATE_ENTRIES %u\n", + TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + break; + case TPM_CAP_PROP_MAX_DAASESS: /* The maximum number of loaded DAA sessions (join or sign) + that the TPM supports */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_MAX\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_DAA_SESSIONS); + break; + case TPM_CAP_PROP_DAASESS: /* The number of available DAA sessions. This may vary with + time and circumstances */ + TPM_DaaSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.daaSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSION_DAA space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_CONTEXT_DIST: /* The maximum distance between context count values. This + MUST be at least 2^16-1. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT_DIST\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, 0xffffffff); + break; + case TPM_CAP_PROP_DAA_INTERRUPT: /* BOOL. A value of TRUE indicates that the TPM will accept + ANY command while executing a DAA Join or Sign. + + A value of FALSE indicates that the TPM will invalidate + the DAA Join or Sign upon the receipt of any command + other than the next join/sign in the session or a + TPM_SaveContext */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_INTERRUPT\n"); + rc = TPM_Sbuffer_Append8(capabilityResponse, TRUE); + break; + case TPM_CAP_PROP_SESSIONS: /* UNIT32. The number of available authorization and transport + sessions from the pool. This may vary with time and + circumstances. */ + TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions); + TPM_TransportSessions_GetSpace(&uint32a, tpm_state->tpm_stclear_data.transSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSIONS %u + %u\n", uint32, uint32a); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32 + uint32a); + break; + case TPM_CAP_PROP_MAX_SESSIONS: /* uint32_t. The maximum number of sessions the + TPM supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_SESSIONS\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, + TPM_MIN_AUTH_SESSIONS + TPM_MIN_TRANS_SESSIONS); + break; + case TPM_CAP_PROP_CMK_RESTRICTION: /* uint32_t TPM_Permanent_Data -> restrictDelegate */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CMK_RESTRICTION %08x\n", + tpm_state->tpm_permanent_data.restrictDelegate); + rc = TPM_Sbuffer_Append32(capabilityResponse, + tpm_state->tpm_permanent_data.restrictDelegate); + break; + case TPM_CAP_PROP_DURATION: + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DURATION\n"); + rc = TPM_GetCapability_CapPropDuration(capabilityResponse); + break; + case TPM_CAP_PROP_ACTIVE_COUNTER: /* TPM_COUNT_ID. The id of the current counter. 0xff..ff if + no counter is active */ + TPM_Counters_GetActiveCounter(&uint32, tpm_state->tpm_stclear_data.countID); + /* The illegal value after releasing an active counter must be mapped back to the null + value */ + if (uint32 == TPM_COUNT_ID_ILLEGAL) { + uint32 = TPM_COUNT_ID_NULL; + } + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_ACTIVE_COUNTER %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_NV_AVAILABLE: /* uint32_t. Deprecated. The maximum number of NV space + that can be allocated, MAY vary with time and + circumstances. This capability was not implemented + consistently, and is replaced by + TPM_NV_INDEX_TRIAL. */ + rc = TPM_NVIndexEntries_GetFreeSpace(&uint32, &(tpm_state->tpm_nv_index_entries)); + if (rc == 0) { + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_NV_AVAILABLE %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + } + /* There should always be free space >= 0. If the call fails here, there is an internal + error. */ + else { + printf(" TPM_GetCapability_CapProperty: Error (fatal) " + "in TPM_CAP_PROP_MAX_NV_AVAILABLE\n"); + rc = TPM_FAIL; + } + break; + case TPM_CAP_PROP_INPUT_BUFFER: /* uint32_t. The size of the TPM input and output buffers in + bytes. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_INPUT_BUFFER %u\n", + TPM_BUFFER_MAX); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_BUFFER_MAX); + break; + default: + printf("TPM_GetCapability_CapProperty: Error, illegal capProperty %08x\n", capProperty); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* TPM_VERSION structure. The Major and Minor must indicate 1.1. + + The manufacturer information MUST indicate the firmware version of the TPM. + + Any software using this structure MUST be aware that when included in a structure the value MUST + be 1.1.0.0, when reported by this command the manufacturer information MAY include firmware + versions. The use of this value is deprecated, new software SHOULD use TPM_CAP_VERSION_VAL to + obtain version information regarding the TPM. + + Return 0.0 for revision for 1.1 backward compatibility, since TPM_PERMANENT_DATA now holds the + new type TPM_VERSION_BYTE. +*/ + +static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + TPM_STRUCT_VER tpm_struct_ver; + + TPM_StructVer_Init(&tpm_struct_ver); + printf(" TPM_GetCapability_CapVersion: %u.%u.%u.%u\n", + tpm_struct_ver.major, tpm_struct_ver.minor, + tpm_struct_ver.revMajor, tpm_struct_ver.revMinor); + rc = TPM_StructVer_Store(capabilityResponse, &tpm_struct_ver); + return rc; +} + +/* A Boolean value. + + TRUE indicates that the TPM has enough memory available to load a key of the type specified by + ALGORITHM. + + FALSE indicates that the TPM does not have enough memory. +*/ + +static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + uint32_t stream_size; + unsigned char *stream; + TPM_KEY_PARMS keyParms; + TPM_BOOL isSpace; + uint32_t index; + + TPM_KeyParms_Init(&keyParms); /* freed @1 */ + if (rc == 0) { + /* make temporary copies so the subCap is not touched */ + stream = subCap->buffer; + stream_size = subCap->size; + rc = TPM_KeyParms_Load(&keyParms, &stream, &stream_size); + } + if (rc == 0) { + if (keyParms.algorithmID == TPM_ALG_RSA) { + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entry); + } + else { + printf(" TPM_GetCapability_CapCheckLoaded: algorithmID %08x is not TPM_ALG_RSA %08x\n", + keyParms.algorithmID, TPM_ALG_RSA); + isSpace = FALSE; + } + } + if (rc == 0) { + printf(" TPM_GetCapability_CapCheckLoaded: Return %02x\n", isSpace); + rc = TPM_Sbuffer_Append(capabilityResponse, &isSpace, sizeof(TPM_BOOL)); + } + TPM_KeyParms_Delete(&keyParms); /* @1 */ + return rc; +} + +/* (Deprecated) This indicates the mode of a symmetric encryption. Mode is Electronic CookBook (ECB) + or some other such mechanism. +*/ + +static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse, + TPM_SYM_MODE symMode) +{ + TPM_RESULT rc = 0; + + symMode = symMode; /* not currently used */ + printf(" TPM_GetCapability_CapSymMode: Return %02x\n", FALSE); + rc = TPM_Sbuffer_Append8(capabilityResponse, FALSE); + return rc; +} + +/* Boolean value of ownerEvict. The handle MUST point to a valid key handle. + */ + +static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t tpm_key_handle) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* corresponding to handle */ + TPM_BOOL ownerEvict; + + printf(" TPM_GetCapability_CapKeyStatus: key handle %08x\n", tpm_key_handle); + /* map from the handle to the TPM_KEY structure */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_GetCapability_CapKeyStatus: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* test the ownerEvict bit */ + if (rc == 0) { + ownerEvict = (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) ? + TRUE : FALSE;; + printf(" TPM_GetCapability_CapKeyStatus: return %02x\n", ownerEvict); + rc = TPM_Sbuffer_Append(capabilityResponse, &ownerEvict, sizeof(TPM_BOOL)); + } + return rc; +} + +/* Manufacturer specific. The manufacturer may provide any additional information regarding the TPM + and the TPM state but MUST not expose any sensitive information. +*/ + +static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + uint32_t subCap32; + + /* all of the subCaps are at least a uint32_t. Some have more data */ + if (rc == 0) { + if (subCap->size >= sizeof(uint32_t)) { + subCap32 = htonl(*(uint32_t *)subCap->buffer); + printf(" TPM_GetCapability_CapMfr: subCap %08x\n", subCap32); + } + else { + printf("TPM_GetCapability_CapMfr: Error, subCap size %u < %lu\n", + subCap->size, (unsigned long)sizeof(uint32_t)); + rc = TPM_BAD_MODE; + } + } + /* switch on the subCap and append the get capability response to the capabilityResponse + buffer */ + if (rc == 0) { + switch(subCap32) { +#ifdef TPM_POSIX + case TPM_CAP_PROCESS_ID: + if (subCap->size == sizeof(uint32_t)) { + pid_t pid = getpid(); + printf(" TPM_GetCapability_CapMfr: TPM_CAP_PROCESS_ID %u\n", (uint32_t)pid); + rc = TPM_Sbuffer_Append32(capabilityResponse, (uint32_t)pid); + } + else { + printf("TPM_GetCapability_CapMfr: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; +#endif + default: + capabilityResponse = capabilityResponse; /* not used */ + tpm_state = tpm_state; /* not used */ + printf("TPM_GetCapability_CapMfr: Error, unsupported subCap %08x\n", subCap32); + rc = TPM_BAD_MODE; + break; + } + } + return rc; +} + +/* Returns a TPM_NV_DATA_PUBLIC structure that indicates the values for the TPM_NV_INDEX +*/ + +static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t nvIndex) +{ + TPM_RESULT rc = 0; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_GetCapability_CapNVIndex: nvIndex %08x\n", nvIndex); + /* map from the nvIndex to the TPM_NV_DATA_PUBLIC structure */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetDataPublic(&tpm_nv_data_public, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + } + /* serialize the structure */ + if (rc == 0) { + rc = TPM_NVDataPublic_Store(capabilityResponse, tpm_nv_data_public, + FALSE); /* do not optimize digestAtRelease */ + } + return rc; +} + +/* Returns a Boolean value. + + TRUE means that the TPM supports the algorithm for TPM_EstablishTransport, TPM_ExecuteTransport + and TPM_ReleaseTransportSigned. + + FALSE indicates that for these three commands the algorithm is not supported." +*/ + +static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapTransAlg: algorithmID %08x\n", algorithmID); + TPM_TransportPublic_CheckAlgId(&supported, algorithmID); + printf(" TPM_GetCapability_CapTransAlg: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Returns a TPM_KEY_HANDLE_LIST structure that enumerates all handles currently loaded in the TPM + for the given resource type. + + TPM_KEY_HANDLE_LIST is the number of handles followed by a list of the handles. + + When describing keys the handle list only contains the number of handles that an external manager + can operate with and does not include the EK or SRK. + + Legal resources are TPM_RT_KEY, TPM_RT_AUTH, TPM_RT_TRANS, TPM_RT_COUNTER + + TPM_RT_CONTEXT is valid and returns not a list of handles but a list of the context count values. +*/ + +static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_RESOURCE_TYPE resourceType) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapHandle: resourceType %08x\n", resourceType); + switch (resourceType) { + case TPM_RT_KEY: + printf(" TPM_GetCapability_CapHandle: TPM_RT_KEY\n"); + rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse, + tpm_state->tpm_key_handle_entries); + break; + case TPM_RT_AUTH: + printf(" TPM_GetCapability_CapHandle: TPM_RT_AUTH\n"); + rc = TPM_AuthSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.authSessions); + break; + case TPM_RT_TRANS: + printf(" TPM_GetCapability_CapHandle: TPM_RT_TRANS\n"); + rc = TPM_TransportSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.transSessions); + break; + case TPM_RT_CONTEXT: + printf(" TPM_GetCapability_CapHandle: TPM_RT_CONTEXT\n"); + rc = TPM_ContextList_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.contextList); + break; + case TPM_RT_COUNTER: + printf(" TPM_GetCapability_CapHandle: TPM_RT_COUNTER\n"); + rc = TPM_Counters_StoreHandles(capabilityResponse, + tpm_state->tpm_permanent_data.monotonicCounter); + break; + case TPM_RT_DAA_TPM: + printf(" TPM_GetCapability_CapHandle: TPM_RT_DAA_TPM\n"); + rc = TPM_DaaSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.daaSessions); + break; + default: + printf("TPM_GetCapability_CapHandle: Error, illegal resource type %08x\n", + resourceType); + rc = TPM_BAD_PARAMETER; + } + return rc; +} + +/* Returns Boolean value. + + TRUE means the TPM supports the encryption scheme in a transport session. +*/ + +static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse, + TPM_ENC_SCHEME encScheme) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapTransEs: encScheme %04hx\n", encScheme); + switch (encScheme) { + /* supported protocols */ + case TPM_ES_SYM_CTR: + case TPM_ES_SYM_OFB: + supported = TRUE; + break; + /* unsupported protocols */ + case TPM_ES_RSAESPKCSv15: + case TPM_ES_RSAESOAEP_SHA1_MGF1: + default: + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapTransEs: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the encryption algorithm in OSAP encryption of AuthData + values +*/ + +static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapAuthEncrypt: algorithmID %08x\n", algorithmID); + switch (algorithmID) { + case TPM_ALG_XOR: + case TPM_ALG_AES128: + /* supported protocols */ + supported = TRUE; + break; + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_MGF1: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + /* unsupported protocols */ + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapAuthEncrypt: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the size for the given version. + + For instance a request could ask for version 1.1 size 2 and the TPM would indicate TRUE. For 1.1 + size 3 the TPM would indicate FALSE. For 1.2 size 3 the TPM would indicate TRUE. +*/ + +static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + TPM_SELECT_SIZE tpm_select_size; + unsigned char *stream; + uint32_t stream_size; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapSelectSize:\n"); + TPM_SelectSize_Init(&tpm_select_size); /* no free required */ + /* deserialize the subCap to the structure */ + if (rc == 0) { + stream = subCap->buffer; + stream_size = subCap->size; + rc = TPM_SelectSize_Load(&tpm_select_size, &stream , &stream_size); + } + if (rc == 0) { + /* The TPM MUST return an error if sizeOfSelect is 0 */ + printf(" TPM_GetCapability_CapSelectSize: subCap reqSize %u\n", + tpm_select_size.reqSize); + if ((tpm_select_size.reqSize > (TPM_NUM_PCR/CHAR_BIT)) || + (tpm_select_size.reqSize == 0)) { + supported = FALSE; + } + else { + supported = TRUE; + } + } + if (rc == 0) { + printf(" TPM_GetCapability_CapSelectSize: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + } + return rc; +} + +#if (TPM_REVISION >= 103) /* added for rev 103 */ +/* TPM_GetCapability_CapDaLogic() rev 100 + + A TPM_DA_INFO or TPM_DA_INFO_LIMITED structure that returns data according to the selected entity + type (e.g., TPM_ET_KEYHANDLE, TPM_ET_OWNER, TPM_ET_SRK, TPM_ET_COUNTER, TPM_ET_OPERATOR, + etc.). If the implemented dictionary attack logic does not support different secret types, the + entity type can be ignored. +*/ + +static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_DA_INFO_LIMITED tpm_da_info_limited; + TPM_DA_INFO tpm_da_info; + + printf(" TPM_GetCapability_CapDaLogic:\n"); + TPM_DaInfoLimited_Init(&tpm_da_info_limited); /* freed @1 */ + TPM_DaInfo_Init(&tpm_da_info); /* freed @2 */ + subCap = subCap; /* dictionary attack mitigation not per entity type in this + implementation. */ + /* if disableFullDALogicInfo is TRUE, the full dictionary attack TPM_GetCapability info is + deactivated. The returned structure is TPM_DA_INFO_LIMITED. */ + if (tpm_state->tpm_permanent_flags.disableFullDALogicInfo) { + TPM_DaInfoLimited_Set(&tpm_da_info_limited, tpm_state); + rc = TPM_DaInfoLimited_Store(capabilityResponse, &tpm_da_info_limited); + + } + /* if disableFullDALogicInfo is FALSE, the full dictionary attack TPM_GetCapability + info is activated. The returned structure is + TPM_DA_INFO. */ + else { + TPM_DaInfo_Set(&tpm_da_info, tpm_state); + rc = TPM_DaInfo_Store(capabilityResponse, &tpm_da_info); + } + TPM_DaInfoLimited_Delete(&tpm_da_info_limited); /* @1 */ + TPM_DaInfo_Delete(&tpm_da_info); /* @2 */ + return rc; +} +#endif + +/* Returns TPM_CAP_VERSION_INFO structure. + + The TPM fills in the structure and returns the information indicating what the TPM currently + supports. +*/ + +static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + TPM_CAP_VERSION_INFO tpm_cap_version_info; + + printf(" TPM_GetCapability_CapVersionVal:\n"); + TPM_CapVersionInfo_Set(&tpm_cap_version_info, tpm_permanent_data); /* freed @1 */ + printf(" TPM_GetCapability_CapVersionVal: specLevel %04hx\n", tpm_cap_version_info.specLevel); + printf(" TPM_GetCapability_CapVersionVal: errataRev %02x\n", tpm_cap_version_info.errataRev); + printf(" TPM_GetCapability_CapVersionVal: revMajor %02x revMinor %02x\n", + tpm_cap_version_info.version.revMajor, tpm_cap_version_info.version.revMinor); + printf(" TPM_GetCapability_CapVersionVal: tpmVendorID %02x %02x %02x %02x\n", + tpm_cap_version_info.tpmVendorID[0], + tpm_cap_version_info.tpmVendorID[1], + tpm_cap_version_info.tpmVendorID[2], + tpm_cap_version_info.tpmVendorID[3]); + rc = TPM_CapVersionInfo_Store(capabilityResponse, &tpm_cap_version_info); + TPM_CapVersionInfo_Delete(&tpm_cap_version_info); /* @1 */ + return rc; +} + +/* Returns a 4 element array of uint32_t values each denoting the timeout value in microseconds for + the following in this order: + + TIMEOUT_A, TIMEOUT_B, TIMEOUT_C, TIMEOUT_D + + Where these timeouts are to be used is determined by the platform specific TPM Interface + Specification. +*/ + +static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapPropTisTimeout:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_A); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_B); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_C); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_D); + } + return rc; +} + +/* Returns a 3 element array of uint32_t values each denoting the duration value in microseconds of + the duration of the three classes of commands: Small, Medium and Long in the following in this + order: + + SMALL_DURATION, MEDIUM_DURATION, LONG_DURATION +*/ + +static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapPropDuration:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_SMALL_DURATION); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MEDIUM_DURATION); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_LONG_DURATION); + } + return rc; +} + +/* 7.3 TPM_GetCapabilityOwner rev 98 + + TPM_GetCapabilityOwner enables the TPM Owner to retrieve all the non-volatile flags and the + volatile flags in a single operation. This command is deprecated, mandatory. + + The flags summarize many operational aspects of the TPM. The information represented by some + flags is private to the TPM Owner. So, for simplicity, proof of ownership of the TPM must be + presented to retrieve the set of flags. When necessary, the flags that are not private to the + Owner can be deduced by Users via other (more specific) means. + + The normal TPM authentication mechanisms are sufficient to prove the integrity of the + response. No additional integrity check is required. + + For 31>=N>=0 + + 1. Bit-N of the TPM_PERMANENT_FLAGS structure is the Nth bit after the opening bracket in the + definition of TPM_PERMANENT_FLAGS in the version of the specification indicated by the parameter + "version". The bit immediately after the opening bracket is the 0th bit. + + 2. Bit-N of the TPM_STCLEAR_FLAGS structure is the Nth bit after the opening bracket in the + definition of TPM_STCLEAR_FLAGS in the version of the specification indicated by the parameter + "version". The bit immediately after the opening bracket is the 0th bit. + + 3. Bit-N of non_volatile_flags corresponds to the Nth bit in TPM_PERMANENT_FLAGS, and the lsb of + non_volatile_flags corresponds to bit0 of TPM_PERMANENT_FLAGS + + 4. Bit-N of volatile_flags corresponds to the Nth bit in TPM_STCLEAR_FLAGS, and the lsb of + volatile_flags corresponds to bit0 of TPM_STCLEAR_FLAGS +*/ + +TPM_RESULT TPM_Process_GetCapabilityOwner(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_AUTHHANDLE authHandle; /* The authorization session handle used for Owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_VERSION version; /* A properly filled out version structure. */ + uint32_t non_volatile_flags; /* The current state of the non-volatile flags. */ + uint32_t volatile_flags; /* The current state of the volatile flags. */ + + printf("TPM_Process_GetCapabilityOwner: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapabilityOwner: 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 validates that the TPM Owner authorizes the command. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM creates the parameter non_volatile_flags by setting each bit to the same state as + the corresponding bit in TPM_PERMANENT_FLAGS. Bits in non_volatile_flags for which there is + no corresponding bit in TPM_PERMANENT_FLAGS are set to zero. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentFlags_StoreBitmap(&non_volatile_flags, + &(tpm_state->tpm_permanent_flags)); + } + /* 3. The TPM creates the parameter volatile_flags by setting each bit to the same state as the + corresponding bit in TPM_STCLEAR_FLAGS. Bits in volatile_flags for which there is no + corresponding bit in TPM_STCLEAR_FLAGS are set to zero. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StclearFlags_StoreBitmap(&volatile_flags, + &(tpm_state->tpm_stclear_flags)); + } + /* 4. The TPM generates the parameter "version". */ + if (returnCode == TPM_SUCCESS) { + TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data)); + } + /* 5. The TPM returns non_volatile_flags, volatile_flags and version to the caller. */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetCapabilityOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the version */ + returnCode = TPM_Version_Store(response, &version); + } + /* return the non_volatile_flags */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, non_volatile_flags); + } + /* return the volatile_flags */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, volatile_flags); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 29.1 TPM_GetCapabilitySigned rev 94 + + TPM_GetCapabilitySigned is almost the same as TPM_GetCapability. The differences are that the + input includes a challenge (a nonce) and the response includes a digital signature to vouch for + the source of the answer. + + If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM + and the caller have AuthData. + + If a caller requires proof for a third party, the signing key must be one whose signature is + trusted by the third party. A TPM-identity key may be suitable. +*/ + +TPM_RESULT TPM_Process_GetCapabilitySigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key that can perform digital + signatures. */ + TPM_NONCE antiReplay; /* Nonce provided to allow caller to defend against replay + of messages */ + TPM_CAPABILITY_AREA capArea = 0; /* Partition of capabilities to be interrogated */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use + of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE;/* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + uint16_t subCap16; /* the subCap as a uint16_t */ + uint32_t subCap32; /* the subCap as a uint32_t */ + TPM_STORE_BUFFER r1Response; /* capability response */ + const unsigned char *r1_buffer; /* r1 serialization */ + uint32_t r1_length; + TPM_DIGEST s1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_VERSION version; /* A properly filled out version structure. */ + TPM_SIZED_BUFFER resp; /* The capability response */ + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_GetCapabilitySigned: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_SizedBuffer_Init(&resp); /* freed @2 */ + TPM_SizedBuffer_Init(&sig); /* freed @3 */ + TPM_Sbuffer_Init(&r1Response); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapabilitySigned: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&subCap, &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, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapabilitySigned: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. The TPM validates the authority to use keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetCapabilitySigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the authorization to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + + + /* subCap is often a uint16_t or uint32_t, create them now */ + if (returnCode == TPM_SUCCESS) { + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + } + /* 2. The TPM calls TPM_GetCapability passing the capArea and subCap fields and saving the resp + field as R1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetCapabilityCommon(&r1Response, tpm_state, + capArea, subCap16, subCap32, &subCap); + } + if (returnCode == TPM_SUCCESS) { + /* get the capability r1 serialization */ + TPM_Sbuffer_Get(&r1Response, &r1_buffer, &r1_length); + printf("TPM_Process_GetCapabilitySigned: resp length %08x\n", r1_length); + TPM_PrintFour("TPM_Process_GetCapabilitySigned: Hashing resp", r1_buffer); + TPM_PrintFour("TPM_Process_GetCapabilitySigned: antiReplay", antiReplay); + /* 3. The TPM creates S1 by taking a SHA1 hash of the concatenation (r1 || antiReplay). */ + returnCode = TPM_SHA1(s1, + r1_length, r1_buffer, + TPM_NONCE_SIZE, antiReplay, + 0, NULL); + } + /* 4. The TPM validates the authority to use keyHandle */ + /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or + TPM_KEY_IDENTITY. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_GetCapabilitySigned: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. The TPM creates a digital signature of S1 using the key in keyHandle and returns the + result in sig. */ + if (returnCode == TPM_SUCCESS) { + if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_GetCapabilitySigned: Error, inappropriate signature scheme %04x\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_GetCapabilitySigned: Signing s1", s1); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + s1, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetCapabilitySigned: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the version */ + TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data)); + returnCode = TPM_Version_Store(response, &version); + } + /* return the capability response size */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, r1_length); + } + /* return the capability response */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, r1_buffer, r1_length); + } + /* return the signature */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&subCap); /* @1 */ + TPM_SizedBuffer_Delete(&resp); /* @2 */ + TPM_SizedBuffer_Delete(&sig); /* @3 */ + TPM_Sbuffer_Delete(&r1Response); /* @4 */ + return rcf; +} + +/* 7.2 TPM_SetCapability rev 96 + + This command sets values in the TPM +*/ + +TPM_RESULT TPM_Process_SetCapability(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_TAG returnCode = 0; /* command return code */ + + /* input parameters */ + TPM_CAPABILITY_AREA capArea; /* Partition of capabilities to be set */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + TPM_SIZED_BUFFER setValue; /* The value to set */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization. HMAC key: owner.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 = FALSE;/* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + uint16_t subCap16; /* the subCap as a uint16_t */ + uint32_t subCap32; /* the subCap as a uint32_t */ + TPM_BOOL ownerAuthorized = FALSE; /* TRUE if owner authorization validated */ + TPM_BOOL presenceAuthorized = FALSE; /* TRUE if physicalPresence validated */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetCapability: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_SizedBuffer_Init(&setValue); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetCapability: capArea %08x \n", capArea); + returnCode = TPM_SizedBuffer_Load(&subCap, &command, ¶mSize); + } + /* get setValue parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&setValue , &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* 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)) { + ownerAuthorized = TRUE; + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetCapability: 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. If tag = TPM_TAG_RQU_AUTH1_COMMAND, validate the command and parameters using ownerAuth, + return TPM_AUTHFAIL on error */ + 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_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* 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, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&presenceAuthorized, tpm_state); + } + /* 2. The TPM validates the capArea and subCap indicators, including the ability to set value + based on any set restrictions */ + /* 3. If the capArea and subCap indicators conform with one of the entries in the structure + TPM_CAPABILITY_AREA (Values for TPM_SetCapability) */ + /* a. The TPM sets the relevant flag/data to the value of setValue parameter. */ + /* 4. Else */ + /* a. Return the error code TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + /* subCap is often a uint16_t or uint32_t, create them now */ + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + returnCode = TPM_SetCapabilityCommon(tpm_state, ownerAuthorized, presenceAuthorized, + capArea, subCap16, subCap32, &subCap, + &setValue); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetCapability: 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) && (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, 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(&subCap); /* @1 */ + TPM_SizedBuffer_Delete(&setValue); /* @2 */ + return rcf; +} + +/* TPM_SetCapabilityCommon() is common code for setting a capability from setValue + + NOTE: This function assumes that the caller has validated either owner authorization or physical + presence! +*/ + +TPM_RESULT TPM_SetCapabilityCommon(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + TPM_BOOL valueBool; + uint32_t valueUint32 = 0; /* start with illegal value */ + + printf(" TPM_SetCapabilityCommon:\n"); + subCap16 = subCap16; /* not used */ + subCap = subCap; /* not used */ + if (rc == 0) { + if ((capArea == TPM_SET_PERM_FLAGS) || + (capArea == TPM_SET_STCLEAR_FLAGS) || + (capArea == TPM_SET_STANY_FLAGS)) { + rc = TPM_SizedBuffer_GetBool(&valueBool, setValue); + } + else if (((capArea == TPM_SET_PERM_DATA) && (subCap32 != TPM_PD_DAAPROOF)) || + (capArea == TPM_SET_STCLEAR_DATA)) { /* deferredPhysicalPresence */ + rc = TPM_SizedBuffer_GetUint32(&valueUint32, setValue); + } + } + if (rc == 0) { + switch (capArea) { + case TPM_SET_PERM_FLAGS: + rc = TPM_SetCapability_CapPermFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_PERM_DATA: + rc = TPM_SetCapability_CapPermData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueUint32); + break; + case TPM_SET_STCLEAR_FLAGS: + rc = TPM_SetCapability_CapStclearFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_STCLEAR_DATA: + rc = TPM_SetCapability_CapStclearData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueUint32); + break; + case TPM_SET_STANY_FLAGS: + rc = TPM_SetCapability_CapStanyFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_STANY_DATA: + rc = TPM_SetCapability_CapStanyData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, setValue); + break; + case TPM_SET_VENDOR: + rc = TPM_SetCapability_CapVendor(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, setValue); + break; + default: + printf("TPM_SetCapabilityCommon: Error, unsupported capArea %08x", capArea); + rc = TPM_BAD_MODE; + break; + } + } + return rc; +} + +/* TPM_SetCapability_Flag() tests if the values are not already equal. If they are not, 'flag' is + set to 'value' and 'altered' is set TRUE. Otherwise 'altered' is returned unchanged. + + The 'altered' flag is used by the caller to determine if an NVRAM write is required. +*/ + +void TPM_SetCapability_Flag(TPM_BOOL *altered, + TPM_BOOL *flag, + TPM_BOOL value) +{ + /* If the values are not already equal. Can't use != since there are many values for TRUE. */ + if ((value && !*flag) || + (!value && *flag)) { + *altered = TRUE; + *flag = value; + } + return; +} + +/* TPM_SetCapability_CapPermFlags() rev 100 + + Sets TPM_PERMANENT_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + TPM_BOOL altered = FALSE; /* TRUE if the structure has been changed */ + + printf(" TPM_SetCapability_CapPermFlags: valueBool %02x\n", valueBool); + if (rc == 0) { + switch (subCap32) { + case TPM_PF_DISABLE: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLE\n"); + /* Owner authorization or physical presence + TPM_OwnerSetDisable + TPM_PhysicalEnable + TPM_PhysicalDisable + */ + if (rc == 0) { + if (!ownerAuthorized && !presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no authorization\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disable), + valueBool); + } + break; + case TPM_PF_OWNERSHIP: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_OWNERSHIP\n"); + /* No authorization. No ownerInstalled. Physical presence asserted + Not available when TPM deactivated or disabled + TPM_SetOwnerInstall + */ + if (rc == 0) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_SetCapability_CapPermFlags: Error, owner installed\n"); + rc = TPM_OWNER_SET; + } + } + if (rc == 0) { + if (!presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.ownership), + valueBool); + } + break; + case TPM_PF_DEACTIVATED: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DEACTIVATED\n"); + /* No authorization, physical presence assertion + Not available when TPM disabled + TPM_PhysicalSetDeactivated + */ + if (rc == 0) { + if (!presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.deactivated), + valueBool); + } + break; + case TPM_PF_READPUBEK: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_READPUBEK\n"); + /* Owner authorization + Not available when TPM deactivated or disabled + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.readPubek), + valueBool); + } + if (rc == 0) { + printf(" TPM_SetCapability_CapPermFlags : readPubek %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + } + break; + case TPM_PF_DISABLEOWNERCLEAR: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEOWNERCLEAR\n"); + /* Owner authorization. Can only set to TRUE, FALSE invalid value. + After being set only ForceClear resets back to FALSE. + Not available when TPM deactivated or disabled + TPM_DisableOwnerClear */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (!valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, cannot set FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disableOwnerClear), + valueBool); + } + break; + case TPM_PF_ALLOWMAINTENANCE: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_ALLOWMAINTENANCE\n"); + /* Owner authorization. Can only set to FALSE, TRUE invalid value. + After being set only changing TPM owner resets back to TRUE + Not available when TPM deactivated or disabled + TPM_KillMaintenanceFeature + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, cannot set TRUE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.allowMaintenance), + valueBool); + } + break; + case TPM_PF_READSRKPUB: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_READSRKPUB\n"); + /* Owner Authorization + Not available when TPM deactivated or disabled + TPM_SetCapability + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disable is TRUE\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated is TRUE\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.readSRKPub), + valueBool); + } + break; + case TPM_PF_TPMESTABLISHED: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_TPMESTABLISHED\n"); + /* Locality 3 or locality 4 + Can only set to FALSE + TPM_ResetEstablishmentBit + */ + if (rc == 0) { + rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, /* BYTE bitmap */ + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, can only set to FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.tpmEstablished), + valueBool); + } + break; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_PF_DISABLEFULLDALOGICINFO: + /* Owner Authorization + TPM_SetCapability + */ + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEFULLDALOGICINFO\n"); + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disableFullDALogicInfo), + valueBool); + } + break; +#endif + case TPM_PF_PHYSICALPRESENCELIFETIMELOCK: + case TPM_PF_PHYSICALPRESENCEHWENABLE: + case TPM_PF_PHYSICALPRESENCECMDENABLE: + case TPM_PF_CEKPUSED: + case TPM_PF_TPMPOST: + case TPM_PF_TPMPOSTLOCK: + case TPM_PF_FIPS: + case TPM_PF_OPERATOR: + case TPM_PF_ENABLEREVOKEEK: + case TPM_PF_NV_LOCKED: + case TPM_PF_MAINTENANCEDONE: + default: + printf("TPM_SetCapability_CapPermFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + rc = TPM_PermanentAll_NVStore(tpm_state, + altered, + rc); + return rc; +} + +/* TPM_SetCapability_CapPermData() rev 105 + + Sets TPM_PERMANENT_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32) +{ + TPM_RESULT rc = 0; + TPM_BOOL writeAllNV = FALSE; /* TRUE if the structure has been changed */ + + printf(" TPM_SetCapability_CapPermData:\n"); + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_PD_RESTRICTDELEGATE: + printf(" TPM_SetCapability_CapPermData: TPM_PD_RESTRICTDELEGATE\n"); + /* Owner authorization. Not available when TPM deactivated or disabled */ + /* TPM_CMK_SetRestrictions */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermData: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermData: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermData: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_data.restrictDelegate != valueUint32) { + tpm_state->tpm_permanent_data.restrictDelegate = valueUint32; + writeAllNV = TRUE; + } + } + break; + case TPM_PD_DAAPROOF: + /* TPM_PD_DAAPROOF This capability has no value. When specified by TPM_SetCapability, a + new daaProof, tpmDAASeed, and daaBlobKey are generated. */ + rc = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + writeAllNV = TRUE; + break; + case TPM_PD_REVMAJOR: + case TPM_PD_REVMINOR: + case TPM_PD_TPMPROOF: + case TPM_PD_OWNERAUTH: + case TPM_PD_OPERATORAUTH: + case TPM_PD_MANUMAINTPUB: + case TPM_PD_ENDORSEMENTKEY: + case TPM_PD_SRK: + case TPM_PD_DELEGATEKEY: + case TPM_PD_CONTEXTKEY: + case TPM_PD_AUDITMONOTONICCOUNTER: + case TPM_PD_MONOTONICCOUNTER: + case TPM_PD_PCRATTRIB: + case TPM_PD_ORDINALAUDITSTATUS: + case TPM_PD_AUTHDIR: + case TPM_PD_RNGSTATE: + case TPM_PD_FAMILYTABLE: + case TPM_DELEGATETABLE: + case TPM_PD_EKRESET: + case TPM_PD_LASTFAMILYID: + case TPM_PD_NOOWNERNVWRITE: + case TPM_PD_TPMDAASEED: + default: + printf("TPM_SetCapability_CapPermData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + rc = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + rc); + return rc; +} + +/* TPM_SetCapability_CapStclearFlags() rev 85 + + Sets TPM_STCLEAR_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStclearFlags: valueBool %02x\n", valueBool); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_SF_DISABLEFORCECLEAR: + printf(" TPM_SetCapability_CapStclearFlags: TPM_SF_DISABLEFORCECLEAR\n"); + /* Not available when TPM deactivated or disabled */ + /* TPM_DisableForceClear */ + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapStclearFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapStclearFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + /* Can only set to TRUE */ + if (rc == 0) { + if (!valueBool) { + printf("TPM_SetCapability_CapStclearFlags: Error, cannot set FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + tpm_state->tpm_stclear_flags.disableForceClear = TRUE; + } + break; + case TPM_SF_DEACTIVATED: + case TPM_SF_PHYSICALPRESENCE: + case TPM_SF_PHYSICALPRESENCELOCK: + case TPM_SF_BGLOBALLOCK: + default: + printf("TPM_SetCapability_CapStclearFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStclearData() rev 100 + + Sets TPM_STCLEAR_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32) +{ + TPM_RESULT rc = 0; +#if (TPM_REVISION < 103) /* added for rev 103 */ + tpm_state = tpm_state; /* to quiet the compiler */ + presenceAuthorized = presenceAuthorized; + valueUint32 = valueUint32; +#endif + + printf(" TPM_SetCapability_CapStclearData:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_SD_DEFERREDPHYSICALPRESENCE: + printf(" TPM_SetCapability_CapStclearData: TPM_SD_DEFERREDPHYSICALPRESENCE\n"); + /* Can only set to TRUE if PhysicalPresence is asserted. Can set to FALSE at any + time. */ + /* 1. If physical presence is not asserted */ + /* a. If TPM_SetCapability -> setValue has a bit set that is not already set in + TPM_STCLEAR_DATA -> deferredPhysicalPresence, return TPM_BAD_PRESENCE. */ + if (rc == 0) { + if (!presenceAuthorized) { + if (~(tpm_state->tpm_stclear_data.deferredPhysicalPresence) & valueUint32) { + printf("TPM_SetCapability_CapStclearData: " + "Error, no physicalPresence and deferredPhysicalPresence %08x\n", + tpm_state->tpm_stclear_data.deferredPhysicalPresence); + rc = TPM_BAD_PRESENCE; + } + } + } + /* 2.Set TPM_STCLEAR_DATA -> deferredPhysicalPresence to TPM_SetCapability -> setValue. + */ + if (rc == 0) { + printf(" TPM_SetCapability_CapStclearData: deferredPhysicalPresence now %08x\n", + valueUint32); + tpm_state->tpm_stclear_data.deferredPhysicalPresence = valueUint32; + } + break; +#endif + case TPM_SD_CONTEXTNONCEKEY: + case TPM_SD_COUNTID: + case TPM_SD_OWNERREFERENCE: + case TPM_SD_DISABLERESETLOCK: + case TPM_SD_PCR: + default: + printf("TPM_SetCapability_CapStclearData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStanyFlags() rev 85 + + Sets TPM_STANY_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStanyFlags:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_AF_TOSPRESENT: + printf(" TPM_SetCapability_CapStanyFlags: TPM_AF_TOSPRESENT\n"); + /* locality 3 or 4 */ + /* Not available when TPM deactivated or disabled */ + if (rc == 0) { + rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapStanyFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapStanyFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + /* can only be set to FALSE */ + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapStanyFlags: Error, cannot set TRUE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + tpm_state->tpm_stany_flags.TOSPresent = FALSE; + } + break; + case TPM_AF_POSTINITIALISE: + case TPM_AF_LOCALITYMODIFIER: + case TPM_AF_TRANSPORTEXCLUSIVE: + default: + printf("TPM_SetCapability_CapStanyFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStanyData() rev 85 + + Sets TPM_STANY_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStanyData:\n"); + tpm_state = tpm_state; /* not used */ + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + setValue = setValue; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_AD_CONTEXTNONCESESSION: + case TPM_AD_AUDITDIGEST: + case TPM_AD_CURRENTTICKS: + case TPM_AD_CONTEXTCOUNT: + case TPM_AD_CONTEXTLIST: + case TPM_AD_SESSIONS: + default: + printf("TPM_SetCapability_CapStanyData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* These are subCaps to TPM_SetCapability -> TPM_SET_VENDOR capArea, the vendor specific area. +*/ + +static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapVendor:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + setValue = setValue; + /* make temporary copies so the setValue is not touched */ + if (rc == 0) { + switch(subCap32) { + default: + printf("TPM_SetCapability_CapVendor: Error, unsupported subCap %08x\n", subCap32); + tpm_state = tpm_state; /* not used */ + rc = TPM_BAD_PARAMETER; + break; + + } + } + return rc; +} diff --git a/src/tpm12/tpm_process.h b/src/tpm12/tpm_process.h new file mode 100644 index 0000000..dfe7b3c --- /dev/null +++ b/src/tpm12/tpm_process.h @@ -0,0 +1,298 @@ +/********************************************************************************/ +/* */ +/* TPM Command Processor */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_process.h 4120 2010-10-26 22:00:40Z 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. */ +/********************************************************************************/ + +#ifndef TPM_PROCESS_H +#define TPM_PROCESS_H + +#include <stdio.h> + +/* Commented out. This is not a standard header. If needed for a particular platform, replace but + also add comments and ifdef. */ +/* #include <stdint.h> */ + +#include "tpm_global.h" +#include "tpm_store.h" + +/* + TPM_CAP_VERSION_INFO +*/ + +void TPM_CapVersionInfo_Init(TPM_CAP_VERSION_INFO *tpm_cap_version_info); +TPM_RESULT TPM_CapVersionInfo_Load(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CapVersionInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CAP_VERSION_INFO *tpm_cap_version_info); +void TPM_CapVersionInfo_Delete(TPM_CAP_VERSION_INFO *tpm_cap_version_info); +void TPM_CapVersionInfo_Set(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + TPM_PERMANENT_DATA *tpm_permanent_data); + +/* + Capability Common Code +*/ + +void TPM_SetCapability_Flag(TPM_BOOL *altered, + TPM_BOOL *flag, + TPM_BOOL value); +void TPM_GetSubCapInt(uint16_t *subCap16, + uint32_t *subCap32, + TPM_SIZED_BUFFER *subCap); + +TPM_RESULT TPM_GetCapabilityCommon(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap); +TPM_RESULT TPM_SetCapabilityCommon(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap, + TPM_SIZED_BUFFER *setValue); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_ProcessA(unsigned char **response, + uint32_t *response_size, + uint32_t *response_total, + unsigned char *command, + uint32_t command_size); +TPM_RESULT TPM_Process(TPM_STORE_BUFFER *response, + unsigned char *command, + uint32_t command_size); +TPM_RESULT TPM_Process_Wrapped(TPM_STORE_BUFFER *response, + unsigned char *command, + uint32_t command_size, + tpm_state_t *targetInstance, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_GetCommandParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_COMMAND_CODE *ordinal, + unsigned char **command, + uint32_t *command_size); +TPM_RESULT TPM_Process_GetResponseParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_RESULT *returnCode, + unsigned char **response, + uint32_t *response_size); + +TPM_RESULT TPM_Process_Unused(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 TPM_Process_GetCapability(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 TPM_Process_GetCapabilityOwner(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 TPM_Process_GetCapabilitySigned(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 TPM_Process_SetCapability(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); + +/* + Processing Utilities +*/ + +/* tag checking */ + +TPM_RESULT TPM_CheckRequestTag210(TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag21 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag2 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag10 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag1 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag0 (TPM_TAG tpm_tag); + +/* TPM state checking */ + +TPM_RESULT TPM_CheckState(tpm_state_t *tpm_state, + TPM_TAG tag, + uint32_t tpm_check_map); +TPM_RESULT TPM_Process_Preprocess(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Check_SHA1Context(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal); + +/* ordinal processing */ + +/* Prototype for all ordinal processing functions + + tpm_state: the entire TPM instance non-volatile and volatile state + response: the buffer to hold the ordinal response + tag: the command tag + paramSize: bytes left after the tag, paramSize, and ordinal + ordinal: the ordinal being called (could be hard coded, but eliminates cut/paste errors) + command: the remainder of the command packet + transportInternal: if not NULL, indicates that this function was called recursively from + TPM_ExecuteTransport +*/ + +typedef TPM_RESULT (*tpm_process_function_t)(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); + +typedef struct tdTPM_ORDINAL_TABLE { + TPM_COMMAND_CODE ordinal; + tpm_process_function_t process_function_v11; /* processing function for TPM 1.1 */ + tpm_process_function_t process_function_v12; /* processing function for TPM 1.2 */ + TPM_BOOL auditable; /* FALSE for functions never audited */ + TPM_BOOL auditDefault; /* TRUE if auditing is enabled by default */ + uint16_t ownerPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t ownerPermissionPosition; /* owner permission bit position */ + uint16_t keyPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t keyPermissionPosition; /* key permission bit position */ + uint32_t inputHandleSize; /* bytes of input handles (or other bytes + not to be encrypted or transport + audited) */ + uint32_t keyHandles; /* number of input key handles */ + uint32_t outputHandleSize; /* bytes of output handles (or other bytes + not to be encrypted or transport + audited */ + TPM_BOOL transportWrappable; /* can be wrapped in transport session */ + TPM_BOOL instanceWrappable; /* ordinal can be wrapped and called by + a parent instance */ + TPM_BOOL hardwareWrappable; /* ordinal can be wrapped and call the + hardware TPM instance */ +} TPM_ORDINAL_TABLE; + +TPM_RESULT TPM_OrdinalTable_GetEntry(TPM_ORDINAL_TABLE **entry, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetProcessFunction(tpm_process_function_t *tpm_process_function, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetAuditable(TPM_BOOL *auditable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetAuditDefault(TPM_BOOL *auditDefault, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_GetOwnerPermission(uint16_t *ownerPermissionBlock, + uint32_t *ownerPermissionPosition, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_GetKeyPermission(uint16_t *keyPermissionBlock, + uint32_t *keyPermissionPosition, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_ParseWrappedCmd(uint32_t *datawStart, + uint32_t *datawLen, + uint32_t *keyHandles, + uint32_t *keyHandle1Index, + uint32_t *keyHandle2Index, + TPM_COMMAND_CODE *ordinal, + TPM_BOOL *transportWrappable, + TPM_SIZED_BUFFER *wrappedCmd); +TPM_RESULT TPM_OrdinalTable_ParseWrappedRsp(uint32_t *datawStart, + uint32_t *datawLen, + TPM_RESULT *rcw, + TPM_COMMAND_CODE ordinal, + const unsigned char *wrappedRspStream, + uint32_t wrappedRspStreamSize); + + +TPM_RESULT TPM_GetInParamDigest(TPM_DIGEST inParamDigest, + TPM_BOOL *auditStatus, + TPM_BOOL *transportEncrypt, + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + unsigned char *inParamStart, + unsigned char *inParamEnd, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_GetOutParamDigest(TPM_DIGEST outParamDigest, + TPM_BOOL auditStatus, + TPM_BOOL transportEncrypt, + TPM_TAG tag, + TPM_RESULT returnCode, + TPM_COMMAND_CODE ordinal, + unsigned char *outParamStart, + uint32_t outParamLength); +TPM_RESULT TPM_ProcessAudit(tpm_state_t *tpm_state, + TPM_BOOL transportEncrypt, + TPM_DIGEST inParamDigest, + TPM_DIGEST outParamDigest, + TPM_COMMAND_CODE ordinal); + +/* + defines for TPM_CheckState check map +*/ + +#define TPM_CHECK_NOT_SHUTDOWN 0x00000001 +#define TPM_CHECK_ENABLED 0x00000004 +#define TPM_CHECK_ACTIVATED 0x00000008 +#define TPM_CHECK_OWNER 0x00000010 +#define TPM_CHECK_NO_LOCKOUT 0x00000020 +#define TPM_CHECK_NV_NOAUTH 0x00000040 + +/* default conditions to check */ +#define TPM_CHECK_ALL 0x0000003f /* all state */ +#define TPM_CHECK_ALLOW_NO_OWNER 0x0000002f /* all state but owner installed */ + +#endif diff --git a/src/tpm12/tpm_secret.c b/src/tpm12/tpm_secret.c new file mode 100644 index 0000000..8dedf14 --- /dev/null +++ b/src/tpm12/tpm_secret.c @@ -0,0 +1,166 @@ +/********************************************************************************/ +/* */ +/* Secret Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_secret.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_store.h" + +#include "tpm_secret.h" + +void TPM_Secret_Init(TPM_SECRET tpm_secret) +{ + printf(" TPM_Secret_Init:\n"); + memset(tpm_secret, 0, TPM_SECRET_SIZE); + return; +} + +/* TPM_Secret_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_Secret_Delete() to free memory +*/ + +TPM_RESULT TPM_Secret_Load(TPM_SECRET tpm_secret, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Load:\n"); + rc = TPM_Loadn(tpm_secret, TPM_SECRET_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Secret_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_Secret_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SECRET tpm_secret) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_secret, TPM_SECRET_SIZE); + return rc; +} + +/* TPM_Secret_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the secret + sets pointers to NULL + calls TPM_Secret_Init to set members back to default values + The secret itself is not freed + returns 0 or error codes +*/ + +void TPM_Secret_Delete(TPM_SECRET tpm_secret) +{ + printf(" TPM_Secret_Delete:\n"); + if (tpm_secret != NULL) { + TPM_Secret_Init(tpm_secret); + } + return; +} + +/* TPM_Secret_Copy() copies the source to the destination + */ + +void TPM_Secret_Copy(TPM_SECRET destination, const TPM_SECRET source) +{ + printf(" TPM_Secret_Copy:\n"); + memcpy(destination, source, TPM_SECRET_SIZE); + return; +} + +/* TPM_Secret_Compare() compares the source to the destination. + + Returns TPM_AUTHFAIL if the nonces are not equal +*/ + +TPM_RESULT TPM_Secret_Compare(TPM_SECRET expect, const TPM_SECRET actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Compare:\n"); + rc = memcmp(expect, actual, TPM_SECRET_SIZE); + if (rc != 0) { + printf("TPM_Secret_Compare: Error comparing secret\n"); + rc = TPM_AUTHFAIL; + } + return rc; +} + +/* TPM_Secret_Generate() generates a new TPM_SECRET from the random number generator + */ + +TPM_RESULT TPM_Secret_Generate(TPM_SECRET tpm_secret) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Generate:\n"); + rc = TPM_Random(tpm_secret, TPM_SECRET_SIZE); + return rc; +} + +/* TPM_Secret_XOR() XOR's the source and the destination, and returns the result on output. + */ + +void TPM_Secret_XOR(TPM_SECRET output, TPM_SECRET input1, TPM_SECRET input2) +{ + size_t i; + + printf(" TPM_Secret_XOR:\n"); + for (i = 0 ; i < TPM_SECRET_SIZE ; i++) { + output[i] = input1[i] ^ input2[i]; + } + return; +} diff --git a/src/tpm12/tpm_secret.h b/src/tpm12/tpm_secret.h new file mode 100644 index 0000000..5621b2e --- /dev/null +++ b/src/tpm12/tpm_secret.h @@ -0,0 +1,62 @@ +/********************************************************************************/ +/* */ +/* Secret Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_secret.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_SECRET_H +#define TPM_SECRET_H + +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_types.h" + +void TPM_Secret_Init(TPM_SECRET tpm_secret); +TPM_RESULT TPM_Secret_Load(TPM_SECRET tpm_secret, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Secret_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SECRET tpm_secret); +void TPM_Secret_Delete(TPM_SECRET tpm_secret); + + +void TPM_Secret_Copy(TPM_SECRET destination, const TPM_SECRET source); +TPM_RESULT TPM_Secret_Compare(TPM_SECRET expect, const TPM_SECRET actual); +TPM_RESULT TPM_Secret_Generate(TPM_SECRET tpm_secret); +void TPM_Secret_XOR(TPM_SECRET output, TPM_SECRET input1, TPM_SECRET input2); + + +#endif diff --git a/src/tpm12/tpm_session.c b/src/tpm12/tpm_session.c new file mode 100644 index 0000000..da6cbe6 --- /dev/null +++ b/src/tpm12/tpm_session.c @@ -0,0 +1,5540 @@ +/********************************************************************************/ +/* */ +/* Session Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_session.c 4584 2011-06-22 15:49:41Z 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 <stdlib.h> +#include <string.h> + +#include "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_permanent.h" +#include "tpm_secret.h" +#include "tpm_transport.h" +#include "tpm_types.h" + +#include "tpm_session.h" + +/* local function prototypes */ + +static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest, + TPM_SECRET **authData, + TPM_AUTH_SESSION_DATA *authSession, + tpm_state_t *tpm_state, + uint32_t delegateRowIndex); + +static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); + +/* + TPM_AUTH_SESSION_DATA (one element of the array) +*/ + +/* TPM_AuthSessionData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuthSessionData_Init(TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + printf(" TPM_AuthSessionData_Init:\n"); + tpm_auth_session_data->handle = 0; + tpm_auth_session_data->protocolID = 0; + tpm_auth_session_data->entityTypeByte = 0; + tpm_auth_session_data->adipEncScheme = 0; + TPM_Nonce_Init(tpm_auth_session_data->nonceEven); + TPM_Secret_Init(tpm_auth_session_data->sharedSecret); + TPM_Digest_Init(tpm_auth_session_data->entityDigest); + TPM_DelegatePublic_Init(&(tpm_auth_session_data->pub)); + tpm_auth_session_data->valid = FALSE; + return; +} + +/* TPM_AuthSessionData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AuthSessionData_Init() + After use, call TPM_AuthSessionData_Delete() to free memory +*/ + +TPM_RESULT TPM_AuthSessionData_Load(TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_Load:\n"); + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_auth_session_data->handle), stream, stream_size); + } + /* load protocolID */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_auth_session_data->protocolID), stream, stream_size); + } + /* load entityTypeByte */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_auth_session_data->entityTypeByte), sizeof(BYTE), stream, stream_size); + } + /* load adipEncScheme */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_auth_session_data->adipEncScheme), sizeof(BYTE), stream, stream_size); + } + /* load nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_auth_session_data->nonceEven, stream, stream_size); + } + /* load sharedSecret */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_auth_session_data->sharedSecret, stream, stream_size); + } + /* load entityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_auth_session_data->entityDigest, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_auth_session_data->pub), stream, stream_size); + } + /* set valid */ + if (rc == 0) { + tpm_auth_session_data->valid = TRUE; + } + return rc; +} + +/* TPM_AuthSessionData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuthSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_Store:\n"); + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_auth_session_data->handle); + } + /* store protocolID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_auth_session_data->protocolID); + } + /* store entityTypeByte */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->entityTypeByte), sizeof(BYTE)); + } + /* store adipEncScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->adipEncScheme), sizeof(BYTE)); + } + /* store nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->nonceEven); + } + /* store sharedSecret */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->sharedSecret); + } + /* store entityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_auth_session_data->entityDigest); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_auth_session_data->pub)); + } + return rc; +} + +/* TPM_AuthSessionData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuthSessionData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuthSessionData_Delete(TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + printf(" TPM_AuthSessionData_Delete:\n"); + if (tpm_auth_session_data != NULL) { + TPM_DelegatePublic_Delete(&(tpm_auth_session_data->pub)); + TPM_AuthSessionData_Init(tpm_auth_session_data); + } + return; +} + +/* TPM_AuthSessionData_Copy() copies the source to the destination. The source handle is ignored, + since it might already be used. +*/ + +void TPM_AuthSessionData_Copy(TPM_AUTH_SESSION_DATA *dest_auth_session_data, + TPM_HANDLE tpm_handle, + TPM_AUTH_SESSION_DATA *src_auth_session_data) +{ + dest_auth_session_data->handle = tpm_handle; + dest_auth_session_data->protocolID = src_auth_session_data->protocolID; + dest_auth_session_data->entityTypeByte = src_auth_session_data->entityTypeByte; + dest_auth_session_data-> adipEncScheme = src_auth_session_data->adipEncScheme; + TPM_Nonce_Copy(dest_auth_session_data->nonceEven, src_auth_session_data->nonceEven); + TPM_Secret_Copy(dest_auth_session_data->sharedSecret, src_auth_session_data->sharedSecret); + TPM_Digest_Copy(dest_auth_session_data->entityDigest, src_auth_session_data->entityDigest); + TPM_DelegatePublic_Copy(&(dest_auth_session_data->pub), &(src_auth_session_data->pub)); + dest_auth_session_data->valid= src_auth_session_data->valid; +} + +/* TPM_AuthSessionData_GetDelegatePublic() */ + +TPM_RESULT TPM_AuthSessionData_GetDelegatePublic(TPM_DELEGATE_PUBLIC **delegatePublic, + TPM_AUTH_SESSION_DATA *auth_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_GetDelegatePublic:\n"); + if (rc == 0) { + *delegatePublic = &(auth_session_data->pub); + } + return rc; +} + +/* TPM_AuthSessionData_CheckEncScheme() checks that the encryption scheme specified by + TPM_ENTITY_TYPE is supported by the TPM (by TPM_AuthSessionData_Decrypt) +*/ + +TPM_RESULT TPM_AuthSessionData_CheckEncScheme(TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_CheckEncScheme: adipEncScheme %02x\n", adipEncScheme); + switch (adipEncScheme) { + case TPM_ET_XOR: + /* i.If TPM_PERMANENT_FLAGS -> FIPS is TRUE */ + /* (1) All encrypted authorizations MUST use a symmetric key encryption scheme. */ + if (FIPS) { + rc = TPM_INAPPROPRIATE_ENC; + } + break; + case TPM_ET_AES128_CTR: + break; + default: + printf("TPM_AuthSessionData_CheckEncScheme: Error, unsupported adipEncScheme\n"); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + return rc; +} + +/* TPM_AuthSessionData_Decrypt() decrypts the encAuth secret using the algorithm indicated in the + OSAP or DSAP session + + If 'odd' is FALSE, one decrypt of encAuthEven to a1Even. + If 'odd' is TRUE, a second decrypt of encAuthOdd to a1Odd is also performed. +*/ + +TPM_RESULT TPM_AuthSessionData_Decrypt(TPM_DIGEST a1Even, + TPM_DIGEST a1Odd, + TPM_ENCAUTH encAuthEven, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_ENCAUTH encAuthOdd, + TPM_BOOL odd) +{ + TPM_RESULT rc = 0; + TPM_DIGEST x1Even; + TPM_DIGEST x2Odd; + + printf(" TPM_AuthSessionData_Decrypt:\n"); + /* sanity check - the session must be OSAP or DSAP */ + if (rc == 0) { + if ((tpm_auth_session_data->protocolID != TPM_PID_OSAP) && + (tpm_auth_session_data->protocolID != TPM_PID_DSAP)) { + printf("TPM_AuthSessionData_Decrypt: Error, protocolID should be OSAP, is %04hx\n", + tpm_auth_session_data->protocolID); + rc = TPM_BAD_MODE; + } + } + if (rc == 0) { + /* algorithm indicated in the OSAP session */ + switch(tpm_auth_session_data->adipEncScheme) { + case TPM_ET_XOR: + /* 4. If the entity type indicates XOR encryption for the AuthData secret */ + /* a.Create X1 the SHA-1 of the concatenation of (authHandle -> sharedSecret || + authLastNonceEven). */ + if (rc == 0) { + rc = TPM_SHA1(x1Even, + TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret, + TPM_NONCE_SIZE, tpm_auth_session_data->nonceEven, + 0, NULL); + } + /* b. Create the decrypted AuthData the XOR of X1 and the encrypted AuthData. */ + if (rc == 0) { + TPM_Digest_XOR(a1Even, encAuthEven, x1Even); + } + /* c. If the command ordinal contains a second AuthData2 secret + (e.g. TPM_CreateWrapKey) */ + /* i. Create X2 the SHA-1 of the concatenation of (authHandle -> sharedSecret || + nonceOdd). */ + if ((rc == 0) && (odd)) { + rc = TPM_SHA1(x2Odd, + TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret, + TPM_NONCE_SIZE, nonceOdd, + 0, NULL); + } + /* ii. Create the decrypted AuthData2 the XOR of X2 and the encrypted AuthData2. */ + if ((rc == 0) && (odd)) { + TPM_Digest_XOR(a1Odd, encAuthOdd, x2Odd); + } + break; +#ifdef TPM_AES /* if AES is supported */ + case TPM_ET_AES128_CTR: + /* 5. If the entity type indicates symmetric key encryption */ + /* a. The key for the encryption algorithm is the first bytes of the OSAP shared + secret. */ + /* i. E.g., For AES128, the key is the first 16 bytes of the OSAP shared secret. */ + /* ii. There is no support for AES keys greater than 128 bits. */ + /* b. If the entity type indicates CTR mode */ + /* i. The initial counter value for AuthData is the first bytes of authLastNonceEven. */ + /* (1) E.g., For AES128, the initial counter value is the first 16 bytes of + authLastNonceEven. */ + /* b. Create the decrypted AuthData from the encrypted AuthData. */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(a1Even, /* output data */ + encAuthEven, /* input data */ + TPM_AUTHDATA_SIZE, /* data size */ + tpm_auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, + tpm_auth_session_data->nonceEven, /* CTR */ + TPM_NONCE_SIZE); + } + /* ii. If the command ordinal contains a second AuthData2 secret + (e.g. TPM_CreateWrapKey) */ + /* (1) The initial counter value for AuthData2 is the first bytes of + nonceOdd. */ + /* ii. Create the decrypted AuthData2 from the the encrypted AuthData2. */ + if ((rc == 0) && (odd)) { + rc = TPM_SymmetricKeyData_CtrCrypt(a1Odd, /* output data */ + encAuthOdd, /* input data */ + TPM_AUTHDATA_SIZE, /* data size */ + tpm_auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, + nonceOdd, /* CTR */ + TPM_NONCE_SIZE); + } + /* iii. Additional counter values as required are generated by incrementing the + entire counter value as a big endian number. */ + break; +#endif /* TPM_AES */ + default: + printf("TPM_AuthSessionData_Decrypt: Error, entityType %02x not supported\n", + tpm_auth_session_data->adipEncScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + } + return rc; +} + +/* + TPM_AUTH_SESSION_DATA (the entire array) +*/ + +void TPM_AuthSessions_Init(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + + printf(" TPM_AuthSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + TPM_AuthSessionData_Init(&(authSessions[i])); + } + return; +} + +/* TPM_AuthSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AuthSessions_Init() +*/ + +TPM_RESULT TPM_AuthSessions_Load(TPM_AUTH_SESSION_DATA *authSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_AuthSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + /* load authorization sessions */ + if (rc == 0) { + if (activeCount > TPM_MIN_AUTH_SESSIONS) { + printf("TPM_AuthSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_AUTH_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_AuthSessions_Load: Loading %u sessions\n", activeCount); + } + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_AuthSessionData_Load(&(authSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_AuthSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuthSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; /* free authorization session slots */ + uint32_t activeCount; /* used authorization session slots */ + + /* store active count */ + if (rc == 0) { + TPM_AuthSessions_GetSpace(&space, authSessions); + activeCount = TPM_MIN_AUTH_SESSIONS - space; + printf(" TPM_AuthSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store auth sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) { + if ((authSessions[i]).valid) { /* if the session is active */ + printf(" TPM_AuthSessions_Store: Storing %08x\n", authSessions[i].handle); + rc = TPM_AuthSessionData_Store(sbuffer, &(authSessions[i])); + } + } + return rc; +} + +/* TPM_AuthSessions_Delete() terminates all sessions + +*/ + +void TPM_AuthSessions_Delete(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + + printf(" TPM_AuthSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + TPM_AuthSessionData_Delete(&(authSessions[i])); + } + return; +} + +/* TPM_AuthSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_AuthSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_AUTH_SESSION_DATA *authSessions) +{ + printf(" TPM_AuthSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_AUTH_SESSIONS ; (*index)++) { + if (!((authSessions[*index]).valid)) { + printf(" TPM_AuthSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +void TPM_AuthSessions_Trace(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if ((authSessions[i]).valid) { + printf(" TPM_AuthSessions_Trace: %lu handle %08x\n", + (unsigned long)i, authSessions[i].handle); + } + } + return; +} + +/* TPM_AuthSessions_GetSpace() returns the number of unused authHandle's. + +*/ + +void TPM_AuthSessions_GetSpace(uint32_t *space, + TPM_AUTH_SESSION_DATA *authSessions) +{ + uint32_t i; + + printf(" TPM_AuthSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if (!((authSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_AuthSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_AuthSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_AuthSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_AuthSessions_GetSpace(&space, authSessions); + /* store loaded handle count. Cast safe because of TPM_MIN_AUTH_SESSIONS value */ + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_AUTH_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) { + if ((authSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (authSessions[i]).handle); /* store it */ + } + } + return rc; +} + +/* TPM_AuthSessions_GetNewHandle() checks for space in the authorization sessions table. + + If there is space, it returns a TPM_AUTH_SESSION_DATA entry in 'tpm_auth_session_data' and its + handle in 'authHandle'. The entry is marked 'valid'. + + If *authHandle non-zero, the suggested value is tried first. + + Returns TPM_RESOURCES if there is no space in the sessions table. +*/ + +TPM_RESULT TPM_AuthSessions_GetNewHandle(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTHHANDLE *authHandle, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_AuthSessions_GetNewHandle:\n"); + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions); + if (!isSpace) { + printf("TPM_AuthSessions_GetNewHandle: Error, no space in authSessions table\n"); + TPM_AuthSessions_Trace(authSessions); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(authHandle, /* I/O */ + authSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_AuthSessions_GetNewHandle: Assigned handle %08x\n", *authHandle); + *tpm_auth_session_data = &(authSessions[index]); + /* assign the handle */ + (*tpm_auth_session_data)->handle = *authHandle; + (*tpm_auth_session_data)->valid = TRUE; + } + return rc; +} + +/* TPM_AuthSessions_GetEntry() searches all entries for the entry matching the handle, and + returns the TPM_AUTH_SESSION_DATA entry associated with the handle. + + Returns + 0 for success + TPM_INVALID_AUTHHANDLE if the handle is not found +*/ + +TPM_RESULT TPM_AuthSessions_GetEntry(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for + authHandle */ + TPM_AUTH_SESSION_DATA *authSessions, /* points to first session + */ + TPM_AUTHHANDLE authHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_AuthSessions_GetEntry: authHandle %08x\n", authHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_AUTH_SESSIONS) && !found ; i++) { + if ((authSessions[i].valid) && + (authSessions[i].handle == authHandle)) { /* found */ + found = TRUE; + *tpm_auth_session_data = &(authSessions[i]); + } + } + if (!found) { + printf(" TPM_AuthSessions_GetEntry: session handle %08x not found\n", + authHandle); + rc = TPM_INVALID_AUTHHANDLE; + } + return rc; +} + +/* TPM_AuthSessions_AddEntry() adds an TPM_AUTH_SESSION_DATA object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_AuthSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_AUTH_SESSION_DATA *authSessions, /* input */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_AuthSessions_AddEntry: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* check for valid TPM_AUTH_SESSION_DATA */ + if (rc == 0) { + if (tpm_auth_session_data == NULL) { /* NOTE: should never occur */ + printf("TPM_AuthSessions_AddEntry: Error (fatal), NULL TPM_AUTH_SESSION_DATA\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions); + if (!isSpace) { + printf("TPM_AuthSessions_AddEntry: Error, session entries full\n"); + TPM_AuthSessions_Trace(authSessions); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + authSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry); + } + if (rc == 0) { + TPM_AuthSessionData_Copy(&(authSessions[index]), *tpm_handle, tpm_auth_session_data); + authSessions[index].valid = TRUE; + printf(" TPM_AuthSessions_AddEntry: Index %u handle %08x\n", + index, authSessions[index].handle); + } + return rc; +} + +/* TPM_AuthSessions_GetData() checks that authHandle indexes a valid TPM_AUTH_SESSION_DATA object. + If so, a pointer to the object is returned in tpm_auth_session_data. + + If required protocolID is either TPM_PID_OIAP or TPM_PID_OSAP, the object is checked for that + type. TPM_PID_OSAP will accept DSAP as well. If it is TPM_PID_NONE, either is accepted. Any + other value is unsupported. + + If the session protocolID is OIAP, the input entityAuth is echoed back as the HMAC key. + entityDigest is ignored and may be NULL. + + If the session protocolID is OSAP or DSAP, the function must check that the entity used to set up + the session is the same as the entity specified in the processing command. It does that by + comparing the entityDigest to that saved during setup of the OSAP session. The shared secret is + returned as the HMAC key. entityAuth is ignored and may be NULL. + + If the session protocolID is DSAP, the TPM_DELEGATE_PUBLIC saved during the TPM_DSAP session + setup is checked for permission and PCR's. The entityType (TPM_ET_KEYHANDLE or TPM_ET_OWNER) is + checked against the TPM_DELEGATE_PUBLIC -> TPM_DELEGATIONS delegateType. Then the bit map is + fetched from the ordinals table and verified against the per1 or per 2 values. The pcrInfo is + checked against the current PCR values. + + The saved entityDigest depends upon the entity type: + + TPM_ET_KEYHANDLE: pubDataDigest + TPM_ET_OWNER: ownerAuth + TPM_ET_SRK: TPM_KEY -> key_digest + TPM_ET_COUNTER: TPM_COUNTER_VALUE -> digest + TPM_ET_NV: TPM_NV_DATA_SENSITIVE -> digest +*/ + +TPM_RESULT TPM_AuthSessions_GetData(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for + authHandle */ + TPM_SECRET **hmacKey, /* output */ + tpm_state_t *tpm_state, /* input */ + TPM_AUTHHANDLE authHandle, /* input */ + TPM_PROTOCOL_ID protocolID, /* input: required protocol */ + TPM_ENT_TYPE entityType, /* input: entity type */ + TPM_COMMAND_CODE ordinal, /* input: for delegation */ + TPM_KEY *tpmKey, /* input, for delegate restrictions */ + TPM_SECRET *entityAuth, /* input OIAP hmac key */ + TPM_DIGEST entityDigest) /* input OSAP session setup auth */ +{ + TPM_RESULT rc = 0; + TPM_DELEGATE_TABLE_ROW *delegateTableRow; + + printf(" TPM_AuthSessions_GetData: authHandle %08x\n", authHandle); + if (rc == 0) { + rc = TPM_AuthSessions_GetEntry(tpm_auth_session_data, + tpm_state->tpm_stclear_data.authSessions, + authHandle); + if (rc != 0) { + printf("TPM_AuthSessions_GetData: Error, authHandle %08x not found\n", authHandle); + } + } + /* If a specific protocol is required, check that the handle points to the correct session type + */ + if (rc == 0) { + switch (protocolID) { /* what protocol is required */ + case TPM_PID_NONE: /* accept any protocol */ + break; + case TPM_PID_OIAP: + if ((*tpm_auth_session_data)->protocolID != TPM_PID_OIAP) { + printf("TPM_AuthSessions_GetData: Error, " + "session protocolID should be OIAP, is %04hx\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_BAD_MODE; + } + break; + case TPM_PID_OSAP: + /* Any ordinal requiring OSAP should also accept DSAP */ + if (((*tpm_auth_session_data)->protocolID != TPM_PID_OSAP) && + ((*tpm_auth_session_data)->protocolID != TPM_PID_DSAP)) { + printf("TPM_AuthSessions_GetData: Error, " + "session protocolID should be OSAP or DSAP, is %04hx\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_BAD_MODE; + } + break; + default: /* should not occur */ + printf("TPM_AuthSessions_GetData: Error, required protocolID %04hx unsupported\n", + protocolID); + rc = TPM_BAD_MODE; + break; + } + } + /* if the entity is owner auth, verify that an owner is installed */ + if (rc == 0) { + if (entityType == TPM_ET_OWNER) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_AuthSessions_GetData: Error, no owner installed\n"); + rc = TPM_AUTHFAIL; + } + } + } + /* session protocol specific processing */ + if (rc == 0) { + switch ((*tpm_auth_session_data)->protocolID) { + case TPM_PID_OIAP: + /* a. If the command using the OIAP session requires owner authorization */ + /* i. If TPM_STCLEAR_DATA -> ownerReference is TPM_KH_OWNER, the secret AuthData is + TPM_PERMANENT_DATA -> ownerAuth */ + /* ii. If TPM_STCLEAR_DATA -> ownerReference is pointing to a delegate row */ + if ((entityType == TPM_ET_OWNER) && + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) { + printf(" TPM_AuthSessions_GetData: Delegating to row %u\n", + tpm_state->tpm_stclear_data.ownerReference); + /* (1) Set R1 a row index to TPM_STCLEAR_DATA -> ownerReference */ + /* (2) Set D1 a TPM_DELEGATE_TABLE_ROW to TPM_PERMANENT_DATA -> delegateTable -> + delRow[R1] */ + if (rc == 0) { + rc = TPM_DelegateTable_GetValidRow + (&delegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + tpm_state->tpm_stclear_data.ownerReference); + } + /* (4) Validate the TPM_DELEGATE_PUBLIC D1 -> pub based on the command ordinal */ + /* (a) Validate D1 -> pub -> permissions based on the command ordinal */ + /* (b) Validate D1 -> pub -> pcrInfo based on the PCR values */ + if (rc == 0) { + rc = TPM_Delegations_CheckPermission(tpm_state, + &(delegateTableRow->pub), + entityType, + ordinal); + } + /* (3) Set the secret AuthData to D1 -> authValue */ + if (rc == 0) { + *hmacKey = &(delegateTableRow->authValue); + } + } + /* not owner or owner but not delegated */ + else { + /* the hmac key is the input authorization secret */ + *hmacKey = entityAuth; + } + break; + case TPM_PID_OSAP: + case TPM_PID_DSAP: /* the first part of DSAP is the same as OSAP */ + /* ensure that the OSAP shared secret is that derived from the entity using OSAP */ + if (rc == 0) { + rc = TPM_Digest_Compare(entityDigest, (*tpm_auth_session_data)->entityDigest); + } + /* extra processing for DSAP sessions */ + if ((*tpm_auth_session_data)->protocolID == TPM_PID_DSAP) { + /* check that delegation is allowed for the ordinal */ + if (rc == 0) { + rc = TPM_Delegations_CheckPermission(tpm_state, + &((*tpm_auth_session_data)->pub), + entityType, /* required for ordinal */ + ordinal); + } + /* check restrictions on delegation of a certified migration key */ + if ((rc == 0) && (entityType == TPM_ET_KEYHANDLE)) { + rc = TPM_Key_CheckRestrictDelegate + (tpmKey, + tpm_state->tpm_permanent_data.restrictDelegate); + } + } + /* the HMAC key is the shared secret calculated during OSAP setup */ + if (rc == 0) { + *hmacKey = &((*tpm_auth_session_data)->sharedSecret); + } + break; + default: /* should not occur */ + printf("TPM_AuthSessions_GetData: session protocolID %04hx unsupported\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* TPM_AuthSessions_TerminateHandle() terminates the session associated with 'authHandle'. + +*/ + +TPM_RESULT TPM_AuthSessions_TerminateHandle(TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle) +{ + TPM_RESULT rc = 0; + TPM_AUTH_SESSION_DATA *tpm_auth_session_data; + + printf(" TPM_AuthSessions_TerminateHandle: Handle %08x\n", authHandle); + /* get the TPM_AUTH_SESSION_DATA associated with the TPM_AUTHHANDLE */ + if (rc == 0) { + rc = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, authSessions, authHandle); + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_AuthSessionData_Delete(tpm_auth_session_data); + } + return rc; +} + +/* TPM_AuthSessions_TerminateEntity() terminates all OSAP and DSAP sessions connected to the + entityType. + + If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for + the ordinal response. + + If the entityDigest is NULL, all sessions are terminated. If entityDigest is not NULL, only + those with a matching entityDigest are terminated. + */ + +void TPM_AuthSessions_TerminateEntity(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_ENT_TYPE entityType, + TPM_DIGEST *entityDigest) +{ + uint32_t i; + TPM_BOOL terminate; + TPM_RESULT match; + + printf(" TPM_AuthSessions_TerminateEntity: entityType %04x\n", entityType); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + terminate = FALSE; + if ((authSessions[i].valid) && /* if the entry is valid */ + ((authSessions[i].protocolID == TPM_PID_OSAP) || /* if it's OSAP or DSAP */ + (authSessions[i].protocolID == TPM_PID_DSAP)) && + (authSessions[i].entityTypeByte == entityType)) { /* connected to entity type */ + /* if entityDigest is NULL, terminate all matching entityType */ + if (entityDigest == NULL) { + terminate = TRUE; + } + /* if entityDigest is not NULL, terminate only those matching entityDigest */ + else { + match = TPM_Digest_Compare(*entityDigest, authSessions[i].entityDigest); + if (match == 0) { + terminate = TRUE; + } + } + } + if (terminate) { + printf(" TPM_AuthSessions_TerminateEntity: Terminating handle %08x\n", + authSessions[i].handle); + /* if terminating the ordinal's session */ + if (authSessions[i].handle == authHandle) { + *continueAuthSession = FALSE; /* for the ordinal response */ + } + TPM_AuthSessionData_Delete(&authSessions[i]); + } + } + return; +} + +/* TPM_AuthSessions_TerminatexSAP terminates all OSAP and DSAP sessions + + If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for + the ordinal response. + + It is safe to call this function during ordinal processing provided a copy of the shared secret + is first saved for the response HMAC calculation. + + The evenNonce is newly created for the response. The oddNonce and continueAuthSession are + command inputs, not part of the session data structure. +*/ + +void TPM_AuthSessions_TerminatexSAP(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions) +{ + uint32_t i; + + printf(" TPM_AuthSessions_TerminatexSAP:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if ((authSessions[i].protocolID == TPM_PID_OSAP) || + (authSessions[i]. protocolID == TPM_PID_DSAP)) { + /* if terminating the ordinal's session */ + if (authSessions[i].handle == authHandle) { + *continueAuthSession = FALSE; /* for the ordinal response */ + } + printf(" TPM_AuthSessions_TerminatexSAP: Terminating handle %08x\n", + authSessions[i].handle); + TPM_AuthSessionData_Delete(&authSessions[i]); + } + } + return; +} + +/* + Context List + + Methods to manipulate the TPM_STANY_DATA->contextList[TPM_MAX_SESSION_LIST] array +*/ + +/* TPM_ContextList_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextList_Init(uint32_t *contextList) +{ + size_t i; + + printf(" TPM_ContextList_Init:\n"); + for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + contextList[i] = 0; + } + return; +} + +/* TPM_ContextList_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextList_Init() +*/ + +TPM_RESULT TPM_ContextList_Load(uint32_t *contextList, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_ContextList_Load:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) { + rc = TPM_Load32(&(contextList[i]), stream, stream_size); + } + return rc; +} + +/* TPM_ContextList_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextList_Store(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_ContextList_Store: Storing %u contexts\n", TPM_MIN_SESSION_LIST); + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]); + } + return rc; +} + +/* TPM_ContextList_GetSpace() returns 'space', the number of unused context list entries. + + If 'space' is non-zero, 'entry' points to the first unused index. +*/ + +void TPM_ContextList_GetSpace(uint32_t *space, + uint32_t *entry, + const uint32_t *contextList) +{ + uint32_t i; + + printf(" TPM_ContextList_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + if (contextList[i] == 0) { /* zero values are free space */ + if (*space == 0) { + *entry = i; /* point to the first non-zero entry */ + } + (*space)++; + } + } + return; +} + +/* TPM_ContextList_GetEntry() gets the entry index corresponding to the value + +*/ + +TPM_RESULT TPM_ContextList_GetEntry(uint32_t *entry, + const uint32_t *contextList, + uint32_t value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextList_GetEntry:\n"); + if (rc == 0) { + if (value == 0) { + printf("TPM_ContextList_GetEntry: Error, value %d never found\n", value); + rc = TPM_BADCONTEXT; + } + } + if (rc == 0) { + for (*entry = 0 ; *entry < TPM_MIN_SESSION_LIST ; (*entry)++) { + if (contextList[*entry] == value) { + break; + } + } + if (*entry == TPM_MIN_SESSION_LIST) { + printf("TPM_ContextList_GetEntry: Error, value %d not found\n", value); + rc = TPM_BADCONTEXT; + } + } + return rc; +} + +/* TPM_ContextList_StoreHandles() stores + + - the number of loaded context entries + - a list of context handles +*/ + +TPM_RESULT TPM_ContextList_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint16_t loaded; + + printf(" TPM_ContextList_StoreHandles:\n"); + if (rc == 0) { + loaded = 0; + /* count the number of loaded handles */ + for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + if (contextList[i] != 0) { + loaded++; + } + } + /* store 'loaded' handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loaded); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST ) ; i++) { + if (contextList[i] != 0) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]); /* store it */ + } + } + return rc; +} + +/* + TPM_CONTEXT_BLOB +*/ + +/* TPM_ContextBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextBlob_Init(TPM_CONTEXT_BLOB *tpm_context_blob) +{ + printf(" TPM_ContextBlob_Init:\n"); + tpm_context_blob->resourceType = 0; + tpm_context_blob->handle = 0; + memset(tpm_context_blob->label, 0, TPM_CONTEXT_LABEL_SIZE); + tpm_context_blob->contextCount = 0; + TPM_Digest_Init(tpm_context_blob->integrityDigest); + TPM_SizedBuffer_Init(&(tpm_context_blob->additionalData)); + TPM_SizedBuffer_Init(&(tpm_context_blob->sensitiveData)); + return; +} + +/* TPM_ContextBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextBlob_Init() + After use, call TPM_ContextBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_ContextBlob_Load(TPM_CONTEXT_BLOB *tpm_context_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CONTEXTBLOB, stream, stream_size); + } + /* load resourceType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->resourceType), stream, stream_size); + } + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->handle), stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE, stream, stream_size); + } + /* load contextCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->contextCount), stream, stream_size); + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_context_blob->integrityDigest, stream, stream_size); + } + /* load additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_blob->additionalData), stream, stream_size); + } + /* load sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_blob->sensitiveData), stream, stream_size); + } + return rc; +} + +/* TPM_ContextBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_BLOB *tpm_context_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXTBLOB); + } + /* store resourceType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->resourceType); + } + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->handle); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE); + } + /* store contextCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->contextCount); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_context_blob->integrityDigest); + } + /* store additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->additionalData)); + } + /* store sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->sensitiveData)); + } + return rc; +} + +/* TPM_ContextBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_ContextBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_ContextBlob_Delete(TPM_CONTEXT_BLOB *tpm_context_blob) +{ + printf(" TPM_ContextBlob_Delete:\n"); + if (tpm_context_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_context_blob->additionalData)); + TPM_SizedBuffer_Delete(&(tpm_context_blob->sensitiveData)); + TPM_ContextBlob_Init(tpm_context_blob); + } + return; +} + +/* + TPM_CONTEXT_SENSITIVE +*/ + +/* TPM_ContextSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextSensitive_Init(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + printf(" TPM_ContextSensitive_Init:\n"); + TPM_Nonce_Init(tpm_context_sensitive->contextNonce); + TPM_SizedBuffer_Init(&(tpm_context_sensitive->internalData)); + return; +} + +/* TPM_ContextSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextSensitive_Init() + After use, call TPM_ContextSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_ContextSensitive_Load(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextSensitive_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CONTEXT_SENSITIVE, stream, stream_size); + } + /* load contextNonce */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_context_sensitive->contextNonce, stream, stream_size); + } + /* load internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_sensitive->internalData), stream, stream_size); + } + return rc; +} + +/* TPM_ContextSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextSensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXT_SENSITIVE); + } + /* store contextNonce */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_context_sensitive->contextNonce); + } + /* store internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_sensitive->internalData)); + } + return rc; +} + +/* TPM_ContextSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_ContextSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_ContextSensitive_Delete(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + printf(" TPM_ContextSensitive_Delete:\n"); + if (tpm_context_sensitive != NULL) { + TPM_SizedBuffer_Delete(&(tpm_context_sensitive->internalData)); + TPM_ContextSensitive_Init(tpm_context_sensitive); + } + return; +} + +/* + Processing Functions +*/ + + +/* 18.1 TPM_OIAP rev 87 + +*/ + +TPM_RESULT TPM_Process_OIAP(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 */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + TPM_BOOL got_handle = FALSE; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* 0, no suggested value */ + + printf("TPM_Process_OIAP: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OIAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM_OIAP command allows the creation of an authorization session handle and the + tracking of the handle by the TPM. The TPM generates the handle and nonce. */ + /* 2. The TPM has an internal limit as to the number of handles that may be open at one time, so + the request for a new handle may fail if there is insufficient space available. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 3. Internally the TPM will do the following: */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OIAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* a. TPM allocates space to save handle, protocol identification, both nonces and any other + information the TPM needs to manage the session. */ + authSession->protocolID = TPM_PID_OIAP; + /* b. TPM generates authHandle and nonceEven, returns these to caller */ + returnCode = TPM_Nonce_Generate(authSession->nonceEven); + } + /* 4. On each subsequent use of the OIAP session the TPM MUST generate a new nonceEven value. */ + /* 5. When TPM_OIAP is wrapped in an encrypted transport session no input or output + parameters encrypted */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OIAP: 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; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + return rcf; +} + +/* 18.2 TPM_OSAP rev 98 + + The TPM_OSAP command creates the authorization handle, the shared secret and generates nonceEven + and nonceEvenOSAP. + + 1 The TPM_OSAP command allows the creation of an authorization handle and the tracking of the + handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP. + + 2. The TPM has an internal limit on the number of handles that may be open at one time, so the + request for a new handle may fail if there is insufficient space available. + + 3. The TPM_OSAP allows the binding of an authorization to a specific entity. This allows the + caller to continue to send in authorization data for each command but not have to request the + information or cache the actual authorization data. + + 4. When TPM_OSAP is wrapped in an encrypted transport session, no input or output parameters are + encrypted + + 5. If the owner pointer is pointing to a delegate row, the TPM internally MUST treat the OSAP + session as a DSAP session + + 6. TPM_ET_SRK or TPM_ET_KEYHANDLE with a value of TPM_KH_SRK MUST specify the SRK. + + 7. If the entity is tied to PCR values, the PCR's are not validated during the TPM_OSAP ordinal + session creation. The PCR's are validated when the OSAP session is used. +*/ + +TPM_RESULT TPM_Process_OSAP(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_ENTITY_TYPE entityType; /* The type of entity in use */ + uint32_t entityValue = 0; /* The selection value based on entityType, e.g. a + keyHandle # */ + TPM_NONCE nonceOddOSAP; /* The nonce generated by the caller associated with + the shared secret. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + TPM_BOOL got_handle = FALSE; + TPM_SECRET *authData; /* usageAuth for the entity */ + TPM_DIGEST *entityDigest = NULL; /* digest of the entity establishing the OSAP + session, initialize to silence compiler */ + TPM_KEY *authKey; /* key to authorize */ + TPM_BOOL parentPCRStatus; + TPM_COUNTER_VALUE *counterValue; /* associated with entityValue */ + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization + state. */ + TPM_NONCE nonceEvenOSAP; /* Nonce generated by TPM and associated with shared + secret. */ + + printf("TPM_Process_OSAP: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + /* get nonceOddOSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityValue %08x\n", entityValue); + returnCode = TPM_Nonce_Load(nonceOddOSAP, &command, ¶mSize); + } + /* 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_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OSAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM creates S1 a storage area that keeps track of the information associated with the + authorization. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* 2. S1 MUST track the following information: */ + /* a. Protocol identification */ + authSession->protocolID = TPM_PID_OSAP; /* save protocol identification */ + authSession->entityTypeByte = entityType & 0x00ff; /* save entity type LSB */ + /* b. nonceEven */ + /* i. Initialized to the next value from the TPM RNG */ + TPM_Nonce_Generate(authSession->nonceEven); + /* c. shared secret NOTE: determined below */ + /* d. ADIP encryption scheme from TPM_ENTITY_TYPE entityType */ + authSession->adipEncScheme = (entityType >> 8) & 0x00ff; /* save entity type MSB */ + /* e. Any other internal TPM state the TPM needs to manage the session */ + /* 3. The TPM MUST create and MAY track the following information */ + /* a. nonceEvenOSAP */ + /* i. Initialized to the next value from the TPM RNG */ + TPM_Nonce_Generate(nonceEvenOSAP); + /* 4. HMAC, shared secret NOTE: determined below */ + /* 5. Check if the ADIP encryption scheme specified by entityType is supported, if not + return TPM_INAPPROPRIATE_ENC. */ + returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + if (returnCode == TPM_SUCCESS) { + switch (authSession->entityTypeByte) { + case TPM_ET_KEYHANDLE: + /* 6. If entityType = TPM_ET_KEYHANDLE */ + /* a. The entity to authorize is a key held in the TPM. entityValue contains the + keyHandle that holds the key. */ + /* b. If entityValue is TPM_KH_OPERATOR return TPM_BAD_HANDLE */ + if (returnCode == TPM_SUCCESS) { + if (entityValue == TPM_KH_OPERATOR) { + printf("TPM_Process_OSAP: Error, " + "entityType TPM_ET_KEYHANDLE entityValue TPM_KH_OPERATOR\n"); + returnCode = TPM_BAD_HANDLE; + } + } + /* look up and get the TPM_KEY authorization data */ + if (returnCode == TPM_SUCCESS) { + /* get the TPM_KEY, entityValue is the handle */ + printf("TPM_Process_OSAP: entityType TPM_ET_KEYHANDLE entityValue %08x\n", + entityValue); + /* TPM_KeyHandleEntries_GetKey() does the mapping from TPM_KH_SRK to the SRK */ + returnCode = TPM_KeyHandleEntries_GetKey(&authKey, + &parentPCRStatus, + tpm_state, + entityValue, + TRUE, /* read only */ + TRUE, /* ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the key */ + entityDigest = &(authKey->tpm_store_asymkey->pubDataDigest); + /* get the usageAuth for the key */ + returnCode = TPM_Key_GetUsageAuth(&authData, authKey); + } + break; + case TPM_ET_OWNER: + /* 7. else if entityType = TPM_ET_OWNER */ + /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */ + /* b. The HMAC key is the secret pointed to by ownerReference (owner secret or delegated + secret) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_OWNER, ownerReference %08x\n", + tpm_state->tpm_stclear_data.ownerReference); + /* verify that an owner is installed */ + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_OSAP: Error, no owner\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* owner reference is owner, use the owner authorization data */ + if (tpm_state->tpm_stclear_data.ownerReference == TPM_KH_OWNER) { + entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth); + authData = &(tpm_state->tpm_permanent_data.ownerAuth); + } + /* Description 5. If the owner pointer is pointing to a delegate row, the TPM + internally MUST treat the OSAP session as a DSAP session */ + else { + returnCode = TPM_OSAPDelegate(&entityDigest, + &authData, + authSession, + tpm_state, + tpm_state->tpm_stclear_data.ownerReference); + } + } + break; + case TPM_ET_SRK: + /* 8. else if entityType = TPM_ET_SRK */ + /* a. The entity to authorize is the SRK. entityValue is ignored. */ + printf("TPM_Process_OSAP: entityType TPM_ET_SRK\n"); + entityDigest = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + returnCode = TPM_Key_GetUsageAuth(&authData, &(tpm_state->tpm_permanent_data.srk)); + break; + case TPM_ET_COUNTER: + /* 9. else if entityType = TPM_ET_COUNTER */ + /* a. The entity is a monotonic counter, entityValue contains the counter handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_COUNTER entityValue %08x\n", + entityValue); + returnCode = + TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + entityValue); + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the counter */ + entityDigest = &(counterValue->digest); + /* get the authData for the counter */ + authData = &(counterValue->authData); + } + break; + case TPM_ET_NV: + /* 10. else if entityType = TPM_ET_NV + a. The entity is a NV index, entityValue contains the NV index */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_NV\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + entityValue); + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the NV data */ + entityDigest = &(tpm_nv_data_sensitive->digest); + /* get the authData for the NV data */ + authData = &(tpm_nv_data_sensitive->authValue); + } + break; + default: + /* 11. else return TPM_INVALID_PARAMETER */ + printf("TPM_Process_OSAP: Error, unknown entityType %04x\n", entityType); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* 2.c. shared secret */ + /* 4. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC + calculation is the secret AuthData assigned to the key handle identified by entityValue. + The input to the HMAC calculation is the concatenation of nonces nonceEvenOSAP and + nonceOddOSAP. The output of the HMAC calculation is the shared secret which is saved in + the authorization area associated with authHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(authSession->entityDigest, *entityDigest); + TPM_PrintFour("TPM_Process_OSAP: entityDigest", *entityDigest); + TPM_PrintFour("TPM_Process_OSAP: authData", *authData); + TPM_PrintFour("TPM_Process_OSAP: nonceEvenOSAP", nonceEvenOSAP); + TPM_PrintFour("TPM_Process_OSAP: nonceOddOSAP", nonceOddOSAP); + returnCode = TPM_HMAC_Generate(authSession->sharedSecret, + *authData, /* HMAC key */ + TPM_NONCE_SIZE, nonceEvenOSAP, + TPM_NONCE_SIZE, nonceOddOSAP, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_OSAP: sharedSecret", authSession->sharedSecret); + } + /* 12. On each subsequent use of the OSAP session the TPM MUST generate a new nonce value. + NOTE: Done as the response is generated. */ + /* 13. The TPM MUST ensure that OSAP shared secret is only available while the OSAP session is + valid. + */ + /* 14. The session MUST terminate upon any of the following conditions: + a. The command that uses the session returns an error + NOTE Done by command + b. The resource is evicted from the TPM or otherwise invalidated + NOTE Done by evict or flush + c. The session is used in any command for which the shared secret is used to encrypt an + input parameter (TPM_ENCAUTH) + NOTE Done by the command + d. The TPM Owner is cleared + NOTE Done by owner clear + e. TPM_ChangeAuthOwner is executed and this session is attached to the owner authorization + NOTE Done by TPM_ChangeAuthOwner + f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific + NOTE Done by the ordinal processing + g. All OSAP sessions associated with the delegation table MUST be invalidated when any of the + following commands execute: + i. TPM_Delegate_Manage + ii. TPM_Delegate_CreateOwnerDelegation with Increment==TRUE + iii. TPM_Delegate_LoadOwnerDelegation + NOTE Done by the ordinal processing + */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OSAP: 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; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* append nonceEvenOSAP */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, nonceEvenOSAP); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + /* + cleanup + */ + return rcf; +} + +/* 18.3 TPM_DSAP rev 106 + + The TPM_DSAP command creates the authorization session handle using a delegated AuthData value + passed into the command as an encrypted blob or from the internal delegation table. It can be + used to start an authorization session for a user key or the owner. + + As in TPM_OSAP, it generates a shared secret and generates nonceEven and nonceEvenOSAP. + + 1. The TPM_DSAP command allows the creation of an authorization session handle and the tracking + of the handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP. + + 2. The TPM has an internal limit on the number of handles that may be open at one time, so the + request for a new handle may fail if there is insufficient space available. + + 3. The TPM_DSAP allows the binding of a delegated authorization to a specific entity. This allows + the caller to continue to send in AuthData for each command but not have to request the + information or cache the actual AuthData. + + 4. On each subsequent use of the DSAP session the TPM MUST generate a new nonce value and check if + the ordinal to be executed has delegation to execute. The TPM MUST ensure that the DSAP shared + secret is only available while the DSAP session is valid. + + 5. When TPM_DSAP is wrapped in an encrypted transport session + a. For input the only parameter encrypted or logged is entityValue + b. For output no parameters are encrypted or logged + + 6. The DSAP session MUST terminate under any of the following conditions + + a. The command that uses the session returns an error + b. If attached to a key, when the key is evicted from the TPM or otherwise invalidated + c. The session is used in any command for which the shared secret is used to encrypt an + input parameter (TPM_ENCAUTH) + d. The TPM Owner is cleared + e. TPM_ChangeAuthOwner is executed and this session is attached to the owner + authorization + f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific + g. All DSAP sessions MUST be invalidated when any of the following commands execute: + + i. TPM_Delegate_CreateOwnerDelegation + (1) When Increment is TRUE + ii. TPM_Delegate_LoadOwnerDelegation + iii. TPM_Delegate_Manage + + NOTE Done by the ordinal processing + + entityType = TPM_ET_DEL_OWNER_BLOB + The entityValue parameter contains a delegation blob structure. + entityType = TPM_ET_DEL_ROW + The entityValue parameter contains a row number in the nv Delegation table which should be + used for the AuthData value. +*/ + +TPM_RESULT TPM_Process_DSAP(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_ENTITY_TYPE entityType; /* The type of delegation information to use */ + TPM_KEY_HANDLE keyHandle = 0; /* Key for which delegated authority corresponds, or 0 if + delegated owner activity. Only relevant if entityValue + equals TPM_DELEGATE_USEKEY_BLOB */ + TPM_NONCE nonceOddDSAP; /* The nonce generated by the caller associated with the + shared secret. */ + TPM_SIZED_BUFFER entityValue; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or + index. MUST not be empty. If entityType is TPM_ET_DEL_ROW + then entityValue is a TPM_DELEGATE_INDEX */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB k1DelegateKeyBlob; + TPM_KEY *delKey; /* key corresponding to keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + uint32_t delegateRowIndex; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow; + TPM_SECRET *a1AuthValue = NULL; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + TPM_BOOL got_handle = FALSE; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization + state. */ + TPM_NONCE nonceEvenDSAP; /* Nonce generated by TPM and associated with shared + secret. */ + + printf("TPM_Process_DSAP: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&entityValue); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&k1DelegateKeyBlob); /* freed @3 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */ + /* + get inputs + */ + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get nonceOddDSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(nonceOddDSAP, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command + sizeof(uint32_t); /* audit entityValue but not entityValueSize */ + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&entityValue, &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_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DSAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = entityValue.buffer; + stream_size = entityValue.size; + switch (entityType & 0x00ff) { /* entity type LSB is the actual entity type */ + case TPM_ET_DEL_OWNER_BLOB: + /* 1. If entityType == TPM_ET_DEL_OWNER_BLOB */ + /* a. Map entityValue to B1 a TPM_DELEGATE_OWNER_BLOB */ + /* b. Validate that B1 is a valid TPM_DELEGATE_OWNER_BLOB, return TPM_WRONG_ENTITYTYPE + on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&b1DelegateOwnerBlob, + &stream, &stream_size); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* c. Locate B1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to + indicate row, return TPM_BADINDEX if not found */ + /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + b1DelegateOwnerBlob.pub.familyID); + } + /* f. Verify that B1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (b1DelegateOwnerBlob.pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + b1DelegateOwnerBlob.pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. Validate the integrity of the blob */ + /* i. Copy B1 -> integrityDigest to H2 */ + /* ii. Set B1 -> integrityDigest to NULL */ + /* iii. Create H3 the HMAC of B1 using tpmProof as the secret */ + /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &b1DelegateOwnerBlob, /* structure */ + b1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store,/* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* h. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting B1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + /* i. Validate S1 values */ + /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* ii. Return TPM_BAD_DELEGATE on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_DecryptEncData + (&s1DelegateSensitive, /* decrypted data */ + &(b1DelegateOwnerBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + /* j. Set A1 to S1 -> authValue */ + if (returnCode == TPM_SUCCESS) { + a1AuthValue = &(s1DelegateSensitive.authValue); + } + break; + case TPM_ET_DEL_ROW: + /* 2. Else if entityType == TPM_ET_DEL_ROW */ + /* a. Verify that entityValue points to a valid row in the delegation table. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&delegateRowIndex, &stream, &stream_size); + } + /* b. Set D1 to the delegation information in the row. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + delegateRowIndex); + } + if (returnCode == TPM_SUCCESS) { + /* c. Set A1 to D1->authValue. */ + a1AuthValue = &d1DelegateTableRow->authValue; + /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate + that row, return TPM_BADINDEX if not found */ + /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1DelegateTableRow->pub.familyID); + } + /* g. Verify that D1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + break; + case TPM_ET_DEL_KEY_BLOB: + /* 3. Else if entityType == TPM_ET_DEL_KEY_BLOB */ + /* a. Map entityValue to K1 a TPM_DELEGATE_KEY_BLOB */ + /* b. Validate that K1 is a valid TPM_DELEGATE_KEY_BLOB, return TPM_WRONG_ENTITYTYPE on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Load(&k1DelegateKeyBlob, &stream, &stream_size); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* c. Locate K1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to + indicate that row, return TPM_BADINDEX if not found */ + /* d. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + k1DelegateKeyBlob.pub.familyID); + } + /* f. Verify that K1 -> pub -> verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (k1DelegateKeyBlob.pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + k1DelegateKeyBlob.pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. Validate the integrity of the blob */ + /* i. Copy K1 -> integrityDigest to H2 */ + /* ii. Set K1 -> integrityDigest to NULL */ + /* iii. Create H3 the HMAC of K1 using tpmProof as the secret */ + /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &k1DelegateKeyBlob, /* structure */ + k1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* h. Validate that K1 -> pubKeyDigest identifies keyHandle, return TPM_KEYNOTFOUND on + error */ + /* get the TPM_KEY corresponding to keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&delKey, + &parentPCRStatus, + tpm_state, + keyHandle, + TRUE, /* read only */ + TRUE, /* ignore PCRs at setup */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_CheckStructure(k1DelegateKeyBlob.pubKeyDigest, + &(delKey->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store, + TPM_KEYNOTFOUND); + } + /* i. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting K1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + /* j. Validate S1 values */ + /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* ii. Return TPM_BAD_DELEGATE on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_DecryptEncData + (&s1DelegateSensitive, /* decrypted data */ + &(k1DelegateKeyBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + /* k. Set A1 to S1 -> authValue */ + if (returnCode == TPM_SUCCESS) { + a1AuthValue = &(s1DelegateSensitive.authValue); + } + break; + default: + /* 4. Else return TPM_BAD_PARAMETER */ + printf("TPM_Process_DSAP: Error, bad entityType %04hx\n", entityType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Generate a new authorization session handle and reserve space to save protocol + identification, shared secret, pcrInfo, both nonces, ADIP encryption scheme, delegated + permission bits and any other information the TPM needs to manage the session. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* save protocol identification */ + authSession->protocolID = TPM_PID_DSAP; + /* save the ADIP encryption scheme */ + authSession->adipEncScheme = (entityType >> 8) & 0x00ff; + /* NOTE: added: Check if the ADIP encryption scheme specified by entityType is supported, if + not return TPM_INAPPROPRIATE_ENC. */ + returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + if (returnCode == TPM_SUCCESS) { + if (entityType == TPM_ET_DEL_KEY_BLOB) { + /* map the entity type to a key */ + authSession->entityTypeByte = TPM_ET_KEYHANDLE; + /* Save the entityDigest for comparison during use. */ + TPM_Digest_Copy(authSession->entityDigest, delKey->tpm_store_asymkey->pubDataDigest); + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + returnCode =TPM_DelegatePublic_Copy(&(authSession->pub), &(k1DelegateKeyBlob.pub)); + } + else { + /* owner or blob or delegate row are both owner auth */ + authSession->entityTypeByte = TPM_ET_OWNER; + /* Save the entityDigest for comparison during use. */ + TPM_Digest_Copy(authSession->entityDigest, tpm_state->tpm_permanent_data.ownerAuth); + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + if (entityType == TPM_ET_DEL_OWNER_BLOB) { + returnCode = TPM_DelegatePublic_Copy(&(authSession->pub), + &(b1DelegateOwnerBlob.pub)); + } + else { /* TPM_ET_DEL_ROW */ + returnCode = TPM_DelegatePublic_Copy(&(authSession->pub), + &(d1DelegateTableRow->pub)); + } + } + /* 6. Read two new values from the RNG to generate nonceEven and nonceEvenOSAP. */ + TPM_Nonce_Generate(authSession->nonceEven); + TPM_Nonce_Generate(nonceEvenDSAP); + } + /* 7. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC + calculation is A1. The input to the HMAC calculation is the concatenation of nonces + nonceEvenOSAP and nonceOddOSAP. The output of the HMAC calculation is the shared secret + which is saved in the authorization area associated with authHandle. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DSAP: authData", *a1AuthValue); + TPM_PrintFour("TPM_Process_DSAP: nonceEvenOSAP", nonceEvenDSAP); + TPM_PrintFour("TPM_Process_DSAP: nonceOddOSAP", nonceOddDSAP); + returnCode = TPM_HMAC_Generate(authSession->sharedSecret, + *a1AuthValue, /* HMAC key */ + TPM_NONCE_SIZE, nonceEvenDSAP, + TPM_NONCE_SIZE, nonceOddDSAP, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DSAP: 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; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* append nonceEvenDSAP */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, nonceEvenDSAP); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&entityValue); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&k1DelegateKeyBlob); /* @3 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */ + return rcf; +} + +/* TPM_DSAPDelegate() implements the actions common to TPM_DSAP and TPM_OSAP with + ownerReference pointing to a delegate row. + + 'entityDigest' and 'authData' are returned, as they are used by common code. + authSession. + + protocolID is changed to DSAP. + the TPM_DELEGATE_PUBLIC blob is copied to the OSAP/DSAP session structure. +*/ + +static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest, + TPM_SECRET **authData, + TPM_AUTH_SESSION_DATA *authSession, + tpm_state_t *tpm_state, + uint32_t delegateRowIndex) +{ + TPM_RESULT rc = 0; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + printf("TPM_DSAPCommon: Index %u\n", delegateRowIndex); + /* 2. Else if entityType == TPM_ET_DEL_ROW */ + /* a. Verify that entityValue points to a valid row in the delegation table. */ + /* b. Set d1 to the delegation information in the row. */ + if (rc == TPM_SUCCESS) { + rc = TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + delegateRowIndex); + } + if (rc == TPM_SUCCESS) { + /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that + row, return TPM_BADINDEX if not found */ + /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + rc = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1DelegateTableRow->pub.familyID); + } + /* g. Verify that d1->verificationCount equals FR -> verificationCount. */ + if (rc == TPM_SUCCESS) { + if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_DSAPCommon: Error, verificationCount mismatch %u %u\n", + d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + rc = TPM_FAMILYCOUNT; + } + } + if (rc == TPM_SUCCESS) { + /* c. Set a1 to d1->authValue. */ + *authData = &d1DelegateTableRow->authValue; /* use owner delegate authorization value */ + /* indicate later that the entity is the 'owner'. Use the real owner auth because the + ordinal doesn't know about the delegation */ + *entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth); + authSession->protocolID = TPM_PID_DSAP; /* change from OSAP to DSAP */ + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + rc = TPM_DelegatePublic_Copy(&(authSession->pub), + &(d1DelegateTableRow->pub)); + } + return rc; +} + +/* 18.4 TPM_SetOwnerPointer rev 109 + + This command will set a reference to which secret the TPM will use when executing an owner secret + related OIAP or OSAP session. + + This command should only be used to provide an owner delegation function for legacy code that + does not itself support delegation. Normally, TPM_STCLEAR_DATA->ownerReference points to + TPM_KH_OWNER, indicating that OIAP and OSAP sessions should use the owner authorization. This + command allows ownerReference to point to an index in the delegation table, indicating that + OIAP and OSAP sessions should use the delegation authorization. + + In use, a TSS supporting delegation would create and load the owner delegation and set the owner + pointer to that delegation. From then on, a legacy TSS application would use its OIAP and OSAP + sessions with the delegated owner authorization. + + Since this command is not authorized, the ownerReference is open to DoS attacks. Applications can + attempt to recover from a failing owner authorization by resetting ownerReference to an + appropriate value. + + This command intentionally does not clear OSAP sessions. A TPM 1.1 application gets the benefit + of owner delegation, while the original owner can use a pre-existing OSAP session with the actual + owner authorization. +*/ + +TPM_RESULT TPM_Process_SetOwnerPointer(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_ENTITY_TYPE entityType; /* The type of entity in use */ + uint32_t entityValue = 0; /* The selection value based on entityType */ + + /* 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_STCLEAR_DATA *v1StClearData; + TPM_DELEGATE_TABLE_ROW *b1DelegateTableRow; /* delegate row indicated by entityValue */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOwnerPointer: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: entityValue %08x\n", entityValue); + } + /* 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_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOwnerPointer: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map TPM_STCLEAR_DATA to V1 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + /* 2. If entityType = TPM_ET_DEL_ROW */ + if (entityType == TPM_ET_DEL_ROW) { + /* a. This value indicates that the entity is a delegate row. entityValue is a delegate + index in the delegation table. */ + /* b. Validate that entityValue points to a legal row within the delegate table stored + within the TPM. If not return TPM_BADINDEX */ + /* i. Set D1 to the delegation information in the row. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_DelegateTable_GetValidRow(&b1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + entityValue); + + } + /* c. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that + row, return TPM_BADINDEX if not found. */ + /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + b1DelegateTableRow->pub.familyID); + } + /* f. Verify that B1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (b1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_SetOwnerPointer: Error, " + "verificationCount mismatch %u %u\n", + b1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. The TPM sets V1-> ownerReference to entityValue */ + /* h. Return TPM_SUCCESS */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n", + entityValue); + v1StClearData->ownerReference = entityValue; + } + } + /* 3. else if entityType = TPM_ET_OWNER */ + else if (entityType == TPM_ET_OWNER) { + /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */ + /* b. The TPM sets V1-> ownerReference to TPM_KH_OWNER */ + /* c. Return TPM_SUCCESS */ + printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n", TPM_KH_OWNER); + v1StClearData->ownerReference = TPM_KH_OWNER; + } + /* 4. Return TPM_BAD_PARAMETER */ + else { + printf("TPM_Process_SetOwnerPointer: Error, bad entityType\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOwnerPointer: 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 27.1.2 TPM_Terminate_Handle rev 87 + + This allows the TPM manager to clear out information in a session handle. + + The TPM may maintain the authorization session even though a key attached to it has been unloaded + or the authorization session itself has been unloaded in some way. When a command is executed + that requires this session, it is the responsibility of the external software to load both the + entity and the authorization session information prior to command execution. + + The TPM SHALL terminate the session and destroy all data associated with the session indicated. +*/ + +TPM_RESULT TPM_Process_TerminateHandle(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_AUTHHANDLE authHandle; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_TerminateHandle: Ordinal Entry\n"); + /* + get inputs + */ + /* get handle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TerminateHandle: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* terminate the handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TerminateHandle: Using authHandle %08x\n", authHandle); + returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + authHandle); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TerminateHandle: 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 */ + } + /* 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); + } + return rcf; +} + +/* 22.1 TPM_FlushSpecific rev 104 + + TPM_FlushSpecific flushes from the TPM a specific handle. + + TPM_FlushSpecific releases the resources associated with the given handle. +*/ + +TPM_RESULT TPM_Process_FlushSpecific(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_HANDLE handle; /* The handle of the item to flush */ + TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being flushed */ + + /* 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 */ + uint32_t r1Resource; /* the context resource being flushed */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_FlushSpecific: Ordinal Entry\n"); + /* + get inputs + */ + /* get handle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&handle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get resourceType parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Handle %08x\n", handle); + returnCode = TPM_Load32(&resourceType, &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_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_FlushSpecific: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_CONTEXT: + /* 1. If resourceType is TPM_RT_CONTEXT */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Flushing context count %08x\n", handle); + /* a. The handle for a context is not a handle but the "context count" value. The + TPM uses the "context count" value to locate the proper contextList entry and + sets R1 to the contextList entry */ + returnCode = TPM_ContextList_GetEntry(&r1Resource, /* index into + contextList[] */ + tpm_state->tpm_stclear_data.contextList, + handle); + /* 7. Validate that R1 determined by resourceType and handle points to a valid + allocated resource. Return TPM_BAD_PARAMETER on error. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Error, context count %08x not found\n", + handle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + if (returnCode == TPM_SUCCESS) { + /* setting the entry to 0 prevents the session from being reloaded. */ + tpm_state->tpm_stclear_data.contextList[r1Resource] = 0; + } + break; + case TPM_RT_KEY: + /* 2. Else if resourceType is TPM_RT_KEY */ + /* a. Set R1 to the key pointed to by handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Flushing key handle %08x\n", handle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + handle); + /* 7. Validate that R1 determined by resourceType and handle points to a valid + allocated resource. Return TPM_BAD_PARAMETER on error. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Error, key handle %08x not found\n", + handle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If R1 -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_FlushSpecific: Error, keyHandle specifies owner evict\n"); + returnCode = TPM_KEY_OWNER_CONTROL; + } + } + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + } + break; + case TPM_RT_AUTH: + /* NOTE replaces deprecated TPM_Terminate_Handle */ + /* 3. Else if resourceType is TPM_RT_AUTH */ + /* a. Set R1 to the authorization session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing authorization session handle %08x\n", + handle); + returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + handle); + break; + case TPM_RT_TRANS: + /* 4. Else if resourceType is TPM_RT_TRANS */ + /* a. Set R1 to the transport session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing transport session handle %08x\n", handle); + returnCode = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + break; + case TPM_RT_DAA_TPM: + /* 5. Else if resourceType is TPM_RT_DAA_TPM */ + /* a. Set R1 to the DAA session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing DAA session handle %08x\n", handle); + returnCode = TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + handle); + break; + default: + /* 6. Else return TPM_INVALID_RESOURCE */ + printf("TPM_Process_FlushSpecific: Error, invalid resourceType %08x\n", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_FlushSpecific: 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 */ + } + /* 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); + } + return rcf; +} + +/* 21.2 TPM_SaveContext rev 107 + + SaveContext saves a loaded resource outside the TPM. After successful execution of the command the + TPM automatically releases the internal memory for sessions but leaves keys in place. + + The caller of the function uses the label field to add additional sequencing, anti-replay or other + items to the blob. The information does not need to be confidential but needs to be part of the + blob integrity. +*/ + +TPM_RESULT TPM_Process_SaveContext(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_HANDLE handle; /* Handle of the resource being saved. */ + TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being saved */ + BYTE label[TPM_CONTEXT_LABEL_SIZE]; /* Label for identification purposes */ + + /* 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_STORE_BUFFER b1_sbuffer; /* serialization of b1 */ + TPM_STCLEAR_DATA *v1StClearData = NULL; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data = NULL; /* session table entry for the handle */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal; /* transport table entry for the handle */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* daa session table entry for the handle */ + TPM_NONCE *n1ContextNonce = NULL; + TPM_SYMMETRIC_KEY_TOKEN k1ContextKey = NULL; + TPM_STORE_BUFFER r1ContextSensitive; /* serialization of sensitive data clear text */ + TPM_CONTEXT_SENSITIVE c1ContextSensitive; + TPM_CONTEXT_BLOB b1ContextBlob; + TPM_STORE_BUFFER c1_sbuffer; /* serialization of c1ContextSensitive */ + uint32_t contextIndex = 0; /* free index in context list */ + uint32_t space; /* free space in context list */ + TPM_BOOL isZero; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveContext: Ordinal Entry\n"); + TPM_Sbuffer_Init(&b1_sbuffer); /* freed @1 */ + TPM_Sbuffer_Init(&r1ContextSensitive); /* freed @2 */ + TPM_ContextBlob_Init(&b1ContextBlob); /* freed @3 */ + TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @4 */ + TPM_Sbuffer_Init(&c1_sbuffer); /* freed @6 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&handle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get resourceType */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: handle %08x\n", handle); + returnCode = TPM_Load32(&resourceType, &command, ¶mSize); + } + /* get label */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: resourceType %08x\n", resourceType); + returnCode = TPM_Loadn(label, TPM_CONTEXT_LABEL_SIZE, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_SaveContext: label", label); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + } + /* 2. Validate that handle points to resource that matches resourceType, return + TPM_INVALID_RESOURCE on error */ + /* 3. Validate that resourceType is a resource from the following list if not return + TPM_INVALID_RESOURCE */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_KEY: + /* a. TPM_RT_KEY */ + printf("TPM_Process_SaveContext: Resource is key handle %08x\n", handle); + /* check if the key handle is valid */ + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + handle); + break; + case TPM_RT_AUTH: + /* b. TPM_RT_AUTH */ + printf("TPM_Process_SaveContext: Resource is session handle %08x\n", handle); + returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, + v1StClearData->authSessions, + handle); + break; + case TPM_RT_TRANS: + /* c. TPM_RT_TRANS */ + printf("TPM_Process_SaveContext: Resource is transport handle %08x\n", handle); + returnCode = TPM_TransportSessions_GetEntry(&tpm_transport_internal, + v1StClearData->transSessions, + handle); + break; + case TPM_RT_DAA_TPM: + /* d. TPM_RT_DAA_TPM */ + printf("TPM_Process_SaveContext: Resource is DAA handle %08x\n", handle); + returnCode = TPM_DaaSessions_GetEntry(&tpm_daa_session_data, + v1StClearData->daaSessions, + handle); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x\n", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + if (returnCode != 0) { + printf("TPM_Process_SaveContext: Error, handle %08x not found\n", handle); + returnCode = TPM_INVALID_RESOURCE; + } + } + /* 4. Locate the correct nonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Locating nonce\n"); + /* a. If resourceType is TPM_RT_KEY */ + if (resourceType == TPM_RT_KEY) { + if (returnCode == TPM_SUCCESS) { + /* i. If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */ + TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey); + if (isZero) { + /* (1) Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM + RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey); + } + } + if (returnCode == TPM_SUCCESS) { + /* ii. Map N1 to TPM_STCLEAR_DATA -> contextNonceKey */ + n1ContextNonce = &(tpm_state->tpm_stclear_data.contextNonceKey); + /* iii. If the key has TPM_KEY_CONTROL_OWNER_EVICT set then return TPM_OWNER_CONTROL + */ + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_SaveContext: Error, key under owner control\n"); + returnCode = TPM_OWNER_CONTROL; + } + } + } + /* b. Else (resource not TPM_RT_KEY) */ + else { + if (returnCode == TPM_SUCCESS) { + /* i. If V1 -> contextNonceSession is NULLS */ + TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession); + if (isZero) { + /* (1) Set V1 -> contextNonceSession to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession); + } + } + /* ii. Map N1 to V1 -> contextNonceSession */ + if (returnCode == TPM_SUCCESS) { + n1ContextNonce = &(v1StClearData->contextNonceSession); + } + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building sensitive data\n"); + /* 5. Set K1 to TPM_PERMANENT_DATA -> contextKey */ + k1ContextKey = tpm_state->tpm_permanent_data.contextKey; + /* 6. Create R1 by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL + sensitive information of the resource is included in R1. */ + /* NOTE Since the contextKey is a symmetric key, the entire resource is put into the + sensitiveData */ + switch (resourceType) { + case TPM_RT_KEY: + returnCode = TPM_KeyHandleEntry_Store(&r1ContextSensitive, tpm_key_handle_entry); + break; + case TPM_RT_AUTH: + returnCode = TPM_AuthSessionData_Store(&r1ContextSensitive, tpm_auth_session_data); + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportInternal_Store(&r1ContextSensitive, tpm_transport_internal); + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessionData_Store(&r1ContextSensitive, tpm_daa_session_data); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* 7. Create C1 a TPM_CONTEXT_SENSITIVE structure */ + /* NOTE Done at TPM_ContextSensitive_Init() */ + /* a. C1 forms the inner encrypted wrapper for the blob. All saved context blobs MUST include a + TPM_CONTEXT_SENSITIVE structure and the TPM_CONTEXT_SENSITIVE structure MUST be encrypted. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building TPM_CONTEXT_SENSITIVE\n"); + /* b. Set C1 -> contextNonce to N1 */ + TPM_Nonce_Copy(c1ContextSensitive.contextNonce, *n1ContextNonce); + /* c. Set C1 -> internalData to R1 */ + returnCode = TPM_SizedBuffer_SetFromStore(&(c1ContextSensitive.internalData), + &r1ContextSensitive); + } + /* 8. Create B1 a TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building TPM_CONTEXT_BLOB\n"); + /* a. Set B1 -> tag to TPM_TAG_CONTEXTBLOB */ + /* NOTE Done at TPM_ContextBlob_Init() */ + /* b. Set B1 -> resourceType to resourceType */ + b1ContextBlob.resourceType = resourceType; + /* c. Set B1 -> handle to handle */ + b1ContextBlob.handle = handle; + /* d. Set B1 -> integrityDigest to NULL */ + /* NOTE Done at TPM_ContextBlob_Init() */ + /* e. Set B1 -> label to label */ + memcpy(b1ContextBlob.label, label, TPM_CONTEXT_LABEL_SIZE); + + } + /* f. Set B1 -> additionalData to information determined by the TPM manufacturer. This data will + help the TPM to reload and reset context. This area MUST NOT hold any data that is sensitive + (symmetric IV are fine, prime factors of an RSA key are not). */ + /* i. For OSAP sessions, and for DSAP sessions attached to keys, the hash of the entity MUST be + included in additionalData */ + /* NOTE Included in TPM_AUTH_SESSION_DATA. This is implementation defined, and the manufacturer + can put everything in sensitive data. */ + /* g. Set B1 -> additionalSize to the size of additionalData */ + /* NOTE Initialized by TPM_ContextBlob_Init() */ + /* h. Set B1 -> sensitiveSize to the size of C1 */ + /* i. Set B1 -> sensitiveData to C1 */ + /* serialize C1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&c1_sbuffer, &c1ContextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(b1ContextBlob.sensitiveData), &c1_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* 9. If resourceType is TPM_RT_KEY */ + if (resourceType == TPM_RT_KEY) { + /* a. Set B1 -> contextCount to 0 */ + b1ContextBlob.contextCount = 0; + } + /* 10. Else */ + else { + printf("TPM_Process_SaveContext: Processing session context count\n"); + if (returnCode == TPM_SUCCESS) { + /* a. If V1 -> contextCount > 2^32-2 then */ + if (v1StClearData->contextCount > 0xfffffffe) { + /* i. Return with TPM_TOOMANYCONTEXTS */ + printf("TPM_Process_SaveContext: Error, too many contexts\n"); + returnCode = TPM_TOOMANYCONTEXTS; + } + } + /* b. Else */ + if (returnCode == TPM_SUCCESS) { + /* i. Validate that the TPM can still manage the new count value */ + /* (1) If the distance between the oldest saved context and the contextCount is + too large return TPM_CONTEXT_GAP */ + /* Since contextCount is uint32_t, this is not applicable here. From email: Does + the TPM have the ability to keep track of the context delta. It is possible to + keep track of things with just a byte or so internally, if this is done a gap of + greater than 2^16 or so might be too large, hence the context gap message */ + } + /* ii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not + found exit with TPM_NOCONTEXTSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList); + if (space == 0) { + printf("TPM_Process_SaveContext: Error, no space in context list\n"); + returnCode = TPM_NOCONTEXTSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* iii. Increment V1 -> contextCount by 1 */ + v1StClearData->contextCount++; + /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */ + v1StClearData->contextList[contextIndex] = v1StClearData->contextCount; + /* v. Set B1 -> contextCount to V1 -> contextCount */ + b1ContextBlob.contextCount = v1StClearData->contextCount; + } + /* c. The TPM MUST invalidate all information regarding the resource except for + information needed for reloading */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_AUTH: + returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, + handle); + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportSessions_TerminateHandle + (v1StClearData->transSessions, + handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions, + handle); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x", + resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + } + } + /* 11. Calculate B1 -> integrityDigest the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as + the secret. NOTE It is calculated on the cleartext data */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (b1ContextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &b1ContextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* 12. Create E1 by encrypting C1 using K1 as the key */ + /* a. Set B1 -> sensitiveSize to the size of E1 */ + /* b. Set B1 -> sensitiveData to E1 */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(b1ContextBlob.sensitiveData)); + returnCode = TPM_SymmetricKeyData_EncryptSbuffer(&(b1ContextBlob.sensitiveData), + &c1_sbuffer, + k1ContextKey); + } + /* 13. Set contextSize to the size of B1 */ + /* 14. Return B1 in contextBlob */ + /* Since the redundant size parameter must be returned, the TPM_CONTEXT_BLOB is serialized + first. Later, rather than the usual _Store to the response, the already serialized buffer is + stored. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&b1_sbuffer, &b1ContextBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveContext: 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 contextSize and contextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &b1_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&b1_sbuffer); /* @1 */ + TPM_Sbuffer_Delete(&r1ContextSensitive); /* @2 */ + TPM_ContextBlob_Delete(&b1ContextBlob); /* @3 */ + TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @4 */ + TPM_Sbuffer_Delete(&c1_sbuffer); /* @6 */ + return rcf; +} + +/* 21.3 TPM_LoadContext rev 107 + + TPM_LoadContext loads into the TPM a previously saved context. The command returns the handle. +*/ + +TPM_RESULT TPM_Process_LoadContext(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_HANDLE entityHandle; /* The handle the TPM MUST use to locate the entity ties + to the OSAP/DSAP session */ + TPM_BOOL keepHandle; /* Indication if the handle MUST be preserved */ + uint32_t contextSize; /* The size of the following context blob */ + TPM_CONTEXT_BLOB b1ContextBlob; /* The context blob */ + + /* 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 key_added = FALSE; /* key has been added to handle list */ + TPM_BOOL auth_session_added = FALSE; + TPM_BOOL trans_session_added = FALSE; + TPM_BOOL daa_session_added = FALSE; + TPM_STCLEAR_DATA *v1StClearData = NULL; + unsigned char *m1Decrypt; /* decrypted sensitive data */ + uint32_t m1_length; /* actual data in m1 */ + unsigned char *stream; + uint32_t stream_size; + TPM_CONTEXT_SENSITIVE c1ContextSensitive; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + TPM_AUTH_SESSION_DATA tpm_auth_session_data; /* loaded authorization session */ + TPM_TRANSPORT_INTERNAL tpm_transport_internal; /* loaded transport session */ + TPM_DAA_SESSION_DATA tpm_daa_session_data; /* loaded daa session */ + TPM_DIGEST entityDigest; /* digest of the entity corresponding to + entityHandle */ + uint32_t contextIndex; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_LoadContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&b1ContextBlob); /* freed @1 */ + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */ + m1Decrypt = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @3 */ + TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */ + TPM_TransportInternal_Init(&tpm_transport_internal); /* freed @5 */ + TPM_DaaSessionData_Init(&tpm_daa_session_data); /* freed @6 */ + /* + get inputs + */ + /* get parameter entityHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&entityHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get keepHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: entityHandle %08x\n", entityHandle); + returnCode = TPM_LoadBool(&keepHandle, &command, ¶mSize); + } + /* get contextSize parameter (redundant, not used) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: keepHandle %02x\n", keepHandle); + returnCode = TPM_Load32(&contextSize, &command, ¶mSize); + } + /* get contextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&b1ContextBlob, &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_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map contextBlob to B1, a TPM_CONTEXT_BLOB structure */ + /* NOTE Done by TPM_ContextBlob_Load() */ + if (returnCode == TPM_SUCCESS) { + /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + v1StClearData = &(tpm_state->tpm_stclear_data); + /* 3. Create M1 by decrypting B1 -> sensitiveData using TPM_PERMANENT_DATA -> contextKey */ + printf("TPM_Process_LoadContext: Decrypting sensitiveData\n"); + returnCode = TPM_SymmetricKeyData_Decrypt(&m1Decrypt, /* decrypted data */ + &m1_length, /* length decrypted data */ + b1ContextBlob.sensitiveData.buffer, /* encrypt */ + b1ContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* 4. Create C1 and R1 by splitting M1 into a TPM_CONTEXT_SENSITIVE structure and internal + resource data */ + /* NOTE R1 is manufacturer specific data that might be part of the blob. This implementation + does not use R1 */ + if (returnCode == TPM_SUCCESS) { + stream = m1Decrypt; + stream_size = m1_length; + returnCode = TPM_ContextSensitive_Load(&c1ContextSensitive, &stream, &stream_size); + } + /* Parse the TPM_CONTEXT_SENSITIVE -> internalData depending on the resource type */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Parsing TPM_CONTEXT_SENSITIVE -> internalData\n"); + stream = c1ContextSensitive.internalData.buffer; + stream_size = c1ContextSensitive.internalData.size; + switch (b1ContextBlob.resourceType) { + case TPM_RT_KEY: + printf("TPM_Process_LoadContext: Loading TPM_KEY_HANDLE_ENTRY\n"); + returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size); + break; + case TPM_RT_AUTH: + printf("TPM_Process_LoadContext: Loading TPM_AUTH_SESSION_DATA\n"); + returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size); + printf("TPM_Process_LoadContext: protocolID %02x entityTypeByte %02x\n", + tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte); + break; + case TPM_RT_TRANS: + printf("TPM_Process_LoadContext: Loading TPM_TRANSPORT_INTERNAL\n"); + returnCode = TPM_TransportInternal_Load(&tpm_transport_internal, + &stream, &stream_size); + break; + case TPM_RT_DAA_TPM: + printf("TPM_Process_LoadContext: Loading TPM_DAA_SESSION_DATA\n"); + returnCode = TPM_DaaSessionData_Load(&tpm_daa_session_data, &stream, &stream_size); + printf("TPM_Process_LoadContext: stage %u\n", + tpm_daa_session_data.DAA_session.DAA_stage); + break; + default: + printf("TPM_Process_LoadContext: Error, invalid resourceType %08x", + b1ContextBlob.resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* 5. Check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Checking contextNonce\n"); + /* a. If B1 -> resourceType is NOT TPM_RT_KEY */ + if (b1ContextBlob.resourceType != TPM_RT_KEY) { + /* i. If C1 -> contextNonce does not equal V1 -> contextNonceSession return + TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession, + c1ContextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Error comparing non-key contextNonce\n"); + returnCode = TPM_BADCONTEXT; + } + } + /* ii. Validate that the resource pointed to by the context is loaded (i.e. for OSAP the + key referenced is loaded and DSAP connected to the key) return TPM_RESOURCEMISSING */ + /* (1) For OSAP sessions and for DSAP sessions attached to keys, the TPM MUST validate + that the hash of the entity matches the entity held by the TPM */ + /* (2) For OSAP and DSAP sessions referring to a key, verify that entityHandle + identifies the key linked to this OSAP/DSAP session, if not return TPM_BAD_HANDLE. */ + if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType == TPM_RT_AUTH)) { + if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) || + (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) { + /* check that the entity is loaded, and get the entity's digest */ + switch (tpm_auth_session_data.entityTypeByte) { + case TPM_ET_KEYHANDLE: + returnCode = TPM_LoadContext_CheckKeyLoaded(tpm_state, + entityHandle, + entityDigest); + break; + case TPM_ET_OWNER: + returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state, + entityDigest); + break; + case TPM_ET_SRK: + returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state, + entityDigest); + break; + case TPM_ET_COUNTER: + returnCode = TPM_LoadContext_CheckCounterLoaded(tpm_state, + entityHandle, + entityDigest); + break; + case TPM_ET_NV: + returnCode = TPM_LoadContext_CheckNvLoaded(tpm_state, + entityHandle, + entityDigest); + break; + default: + printf("TPM_Process_LoadContext: Error, invalid session entityType %02x\n", + tpm_auth_session_data.entityTypeByte); + returnCode = TPM_WRONG_ENTITYTYPE; + break; + } + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Error, " + "OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + } + } + } + /* b. Else (TPM_RT_KEY) */ + else { + /* i. If C1 -> internalData -> parentPCRStatus is FALSE and C1 -> internalData -> + isVolatile is FALSE */ + /* NOTE parentPCRStatus and keyFlags are not security sensitive data, could be in + additionalData */ + /* (1) Ignore C1 -> contextNonce */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry.parentPCRStatus || + (tpm_key_handle_entry.key->keyFlags & TPM_ISVOLATILE)) { + /* ii. else */ + /* (1) If C1 -> contextNonce does not equal TPM_STCLEAR_DATA -> contextNonceKey + return TPM_BADCONTEXT */ + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceKey, + c1ContextSensitive.contextNonce); + if (returnCode != 0) { + printf("TPM_Process_LoadContext: Error comparing contextNonceKey\n"); + returnCode = TPM_BADCONTEXT; + } + } + } + } + } + /* 6. Validate the structure */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Checking integrityDigest\n"); + /* a. Set H1 to B1 -> integrityDigest */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* b. Set B1 -> integrityDigest to all zeros */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */ + returnCode = TPM_SizedBuffer_Set(&(b1ContextBlob.sensitiveData), m1_length, m1Decrypt); + } + /* d. Create H2 the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as the HMAC key */ + /* e. If H2 does not equal H1 return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &b1ContextBlob, /* structure */ + b1ContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* 9. If B1 -> resourceType is NOT TPM_RT_KEY */ + if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType != TPM_RT_KEY)) { + printf("TPM_Process_LoadContext: Checking contextCount\n"); + /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 -> + TPM_CONTEXT_BLOB -> contextCount */ + /* b. If not found then return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextList_GetEntry(&contextIndex, + v1StClearData->contextList, + b1ContextBlob.contextCount); + } + /* c. Set V1 -> contextList[contextIndex] to 0 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData->contextList[contextIndex] = 0; + } + } + /* 10. Process B1 to return the resource back into TPM use */ + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Adding entry to table\n"); + switch (b1ContextBlob.resourceType) { + case TPM_RT_KEY: + returnCode = TPM_KeyHandleEntries_AddEntry(&(b1ContextBlob.handle), + keepHandle, + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + key_added = TRUE; + break; + case TPM_RT_AUTH: + returnCode = TPM_AuthSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->authSessions, + &tpm_auth_session_data); + auth_session_added = TRUE; + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->transSessions, + &tpm_transport_internal); + trans_session_added = TRUE; + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->daaSessions, + &tpm_daa_session_data); + daa_session_added = TRUE; + break; + default: + printf("TPM_Process_LoadContext: Error, invalid resourceType %08x\n", + b1ContextBlob.resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadContext: 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) { + /* return handle */ + returnCode = TPM_Sbuffer_Append32(response, b1ContextBlob.handle); + /* 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(tpm_key_handle_entry.key); /* free on error */ + free(tpm_key_handle_entry.key); /* free on error */ + if (key_added) { + /* if there was a failure and inKey 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, + b1ContextBlob.handle); + } + if (auth_session_added) { + TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, b1ContextBlob.handle); + } + if (trans_session_added) { + TPM_TransportSessions_TerminateHandle(v1StClearData->transSessions, + b1ContextBlob.handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + if (daa_session_added) { + TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions, b1ContextBlob.handle); + } + } + TPM_ContextBlob_Delete(&b1ContextBlob); /* @1 */ + free(m1Decrypt); /* @2 */ + TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @3 */ + TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */ + TPM_TransportInternal_Delete(&tpm_transport_internal); /* @5 */ + TPM_DaaSessionData_Delete(&tpm_daa_session_data); /* @6 */ + return rcf; +} + +/* TPM_LoadContext_CheckKeyLoaded() validates that the key associated with a loading authorization + context is loaded. + + It returns the key pubDataDigest for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *key_handle_entry; + + printf("TPM_LoadContext_CheckKeyLoaded: handle %08x\n", entityHandle); + /* get the key associated with entityHandle */ + /* special case, SRK is not in the key handle list */ + if (entityHandle == TPM_KH_SRK) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + TPM_Digest_Copy(entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + else { + printf("TPM_LoadContext_CheckKeyLoaded: Error, ownerInstalled is FALSE\n"); + rc = TPM_NOSRK; + } + } + /* normal case, key is in the key handle list */ + else { + rc = TPM_KeyHandleEntries_GetEntry(&key_handle_entry, + tpm_state->tpm_key_handle_entries, + entityHandle); + if (rc == 0) { + TPM_Digest_Copy(entityDigest, key_handle_entry->key->tpm_store_asymkey->pubDataDigest); + } + else { + printf("TPM_LoadContext_CheckKeyLoaded: Error, key handle %08x not found\n", + entityHandle); + rc = TPM_BAD_HANDLE; + } + } + return rc; +} + +/* TPM_LoadContext_CheckKeyLoadedByDigest() validates that the key associated with a loading + authorization context is loaded. + + It compares the key the pubDataDigest to the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = TPM_RETRY; /* any non-zero value will do */ + size_t start; + size_t current; + TPM_KEY_HANDLE_ENTRY *key_handle_entry; + + printf("TPM_LoadContext_CheckKeyLoadedByDigest:\n"); + /* get the key associated with entityDigest */ + start = 0; + /* iterate through all keys in the key handle table */ + while ((rc != 0) && /* a match sets rc to 0, terminates loop */ + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + + + start = current + 1; + rc = TPM_Digest_Compare(entityDigest, + key_handle_entry->key->tpm_store_asymkey->pubDataDigest); + } + /* if that failed, check the SRK */ + if (rc != 0) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + rc = TPM_Digest_Compare + (entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + } + if (rc != 0) { + printf("TPM_LoadContext_CheckKeyLoadedByDigest: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + rc = TPM_RESOURCEMISSING; + } + return rc; +} + +/* TPM_LoadContext_CheckOwnerLoaded() validates that the owner is loaded. + + It returns the owner authorization for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + + printf("TPM_LoadContext_CheckOwnerLoaded:\n"); + /* verify that an owner is installed */ + if (rc == 0) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_LoadContext_CheckOwnerLoaded: Error, no owner\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, tpm_state->tpm_permanent_data.ownerAuth); + } + return rc; +} + +/* TPM_LoadContext_CheckSrkLoaded() validates that the SRK is loaded. + + It returns the SRK pubDataDigest for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + + printf("TPM_LoadContext_CheckSrkLoaded:\n"); + /* verify that an owner is installed */ + if (rc == 0) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_LoadContext_CheckSrkLoaded: Error, no SRK\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + return rc; +} + +/* TPM_LoadContext_CheckCounterLoaded() validates that the counter associated with a loading + authorization context is loaded. + + It returns the counter authorization for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + TPM_COUNTER_VALUE *counterValue; /* associated with entityHandle */ + + printf("TPM_LoadContext_CheckCounterLoaded: handle %08x\n", entityHandle); + if (rc == 0) { + rc = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + entityHandle); + if (rc != 0) { + printf("TPM_LoadContext_CheckCounterLoaded: Error, no counter\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, counterValue->digest); + } + return rc; +} + +/* TPM_LoadContext_CheckNvLoaded() validates that the NV space associated with a loading + authorization context exists. +*/ + +static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + + TPM_RESULT rc = 0; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */ + + printf(" TPM_LoadContext_CheckNvLoaded: handle %08x\n", entityHandle); + if (rc == 0) { + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + entityHandle); + if (rc != 0) { + printf("TPM_LoadContext_CheckNvLoaded: Error, no NV at index %08x\n", entityHandle); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, tpm_nv_data_sensitive->digest); + } + return rc; +} + +/* 21.1 TPM_KeyControlOwner rev 116 + + This command controls some attributes of keys that are stored within the TPM key cache. + + 1. Set an internal bit within the key cache that controls some attribute of a loaded key. + + 2.When a key is set to ownerEvict, the key handle value remains the same as long as the key + remains ownerEvict. The key handle value persists through TPM_Startup. + + OwnerEvict: If this bit is set to true, this key remains in the TPM non-volatile storage + through all TPM_Startup events. The only way to evict this key is for the TPM Owner to + execute this command again, setting the owner control bit to false and then executing + TPM_FlushSpecific. + + The key handle does not reference an authorized entity and is not validated. + + The check for two remaining key slots ensures that users can load the two keys required to + execute many commands. Since only the owner can flush owner evict keys, non-owner commands + could be blocked if this test was not performed. +*/ + +TPM_RESULT TPM_Process_KeyControlOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key. */ + TPM_PUBKEY pubKey; /* The public key associated with the loaded key */ + TPM_KEY_CONTROL bitName = 0; /* The name of the bit to be modified */ + TPM_BOOL bitValue = FALSE; /* The value to set the bit to */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC authorization: key ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* 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_HANDLE_ENTRY *tpm_key_handle_entry; /* entry for keyHandle */ + TPM_BOOL isSpace; + TPM_BOOL oldOwnerEvict; /* original owner evict state */ + uint16_t ownerEvictCount; /* current number of owner evict keys */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_KeyControlOwner: Ordinal Entry\n"); + TPM_Pubkey_Init(&pubKey); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pubKey parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: keyHandle %08x\n", keyHandle); + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* get bitName parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bitName, &command, ¶mSize); + } + /* get bitValue parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load8(&bitValue, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: bitName %08x bitValue %02x\n", bitName, bitValue); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_KeyControlOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData using the owner authentication value, on error return TPM_AUTHFAIL + */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle refers to a loaded key, return TPM_INVALID_KEYHANDLE on error. */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyHandle); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: Error, key handle not loaded\n"); + returnCode = TPM_INVALID_KEYHANDLE; + } + } + /* If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, TPM_KEY_BIND, or TPM_KEY_LEGACY, the TPM + must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_key_handle_entry->key->keyUsage != TPM_KEY_SIGNING) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_STORAGE) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_IDENTITY) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_BIND) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_KeyControlOwner: Error, invalid key keyUsage %04hx\n", + tpm_key_handle_entry->key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Validate that pubKey matches the key held by the TPM pointed to by keyHandle, return + TPM_BAD_PARAMETER on mismatch */ + /* a. This check is added so that virtualization of the keyHandle does not result in attacks, as + the keyHandle is not associated with an authorization value */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_ComparePubkey(tpm_key_handle_entry->key, &pubKey); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: Error comparing pubKey\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 4. Validate that bitName is valid, return TPM_BAD_MODE on error. NOTE Valid means a legal + TPM_KEY_CONTROL value */ + if (returnCode == TPM_SUCCESS) { + switch(bitName) { + /* 5. If bitName == TPM_KEY_CONTROL_OWNER_EVICT */ + case TPM_KEY_CONTROL_OWNER_EVICT: + /* save the old value to determine if NVRAM update is necessary */ + oldOwnerEvict = tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT; + /* a. If bitValue == TRUE */ + if (bitValue) { + printf("TPM_Process_KeyControlOwner: setting key owner evict\n"); + if (!oldOwnerEvict) { /* if the key is not owner evict */ + /* i. Verify that after this operation at least two key slots will be present + within the TPM that can store any type of key both of which do NOT have the + OwnerEvict bit set, on error return TPM_NOSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_KeyHandleEntries_IsEvictSpace(&isSpace, + tpm_state->tpm_key_handle_entries, + 2); /* minSpace */ + if (!isSpace) { + printf("TPM_Process_KeyControlOwner: Error, " + "Need 2 non-evict slots\n"); + returnCode = TPM_NOSPACE; + } + } + /* ii. Verify that for this key handle, parentPCRStatus is FALSE and isVolatile + is FALSE. Return TPM_BAD_PARAMETER on error. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->parentPCRStatus || + tpm_key_handle_entry->key->keyFlags & TPM_ISVOLATILE) { + printf("TPM_Process_KeyControlOwner: Error, " + "parentPCRStatus or Volatile\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* check the current number of occupied owner evict key slots */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_OwnerEvictGetCount + (&ownerEvictCount, + tpm_state->tpm_key_handle_entries); + } + /* check that the number of owner evict key slots will not be exceeded */ + if (returnCode == TPM_SUCCESS) { + if (ownerEvictCount == TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_Process_KeyControlOwner: Error, " + "no evict space, only %u evict slots\n", + TPM_OWNER_EVICT_KEY_HANDLES); + returnCode = TPM_NOSPACE; + } + } + /* iii. Set ownerEvict within the internal key storage structure to TRUE. */ + if (returnCode == TPM_SUCCESS) { + tpm_key_handle_entry->keyControl |= TPM_KEY_CONTROL_OWNER_EVICT; + } + /* if the old value was FALSE, write the entry to NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + else { /* if the key is already owner evict, nothing to do */ + printf("TPM_Process_KeyControlOwner: key is already owner evict\n"); + } + } + /* b. Else if bitValue == FALSE */ + else { + if (oldOwnerEvict) { /* if the key is currently owner evict */ + printf("TPM_Process_KeyControlOwner: setting key not owner evict\n"); + /* i. Set ownerEvict within the internal key storage structure to FALSE. */ + if (returnCode == TPM_SUCCESS) { + tpm_key_handle_entry->keyControl &= ~TPM_KEY_CONTROL_OWNER_EVICT; + } + /* if the old value was TRUE, delete the entry from NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + else { /* if the key is already not owner evict, nothing to do */ + printf("TPM_Process_KeyControlOwner: key is already not owner evict\n"); + } + } + break; + default: + printf("TPM_Process_KeyControlOwner: Invalid bitName %08x\n", bitName); + returnCode = TPM_BAD_MODE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_KeyControlOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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_Pubkey_Delete(&pubKey); /* @1 */ + return rcf; +} + +/* 27.2 Context management + + The 1.1 context commands were written for specific resource types. The 1.2 commands are generic + for all resource types. So the Savexxx commands are replaced by TPM_SaveContext and the LoadXXX + commands by TPM_LoadContext. +*/ + +/* 27.2.1 TPM_SaveKeyContext rev 87 + + SaveKeyContext saves a loaded key outside the TPM. After creation of the key context blob the TPM + automatically releases the internal memory used by that key. The format of the key context blob is + specific to a TPM. +*/ + +TPM_RESULT TPM_Process_SaveKeyContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The key which will be kept outside the TPM */ + + /* 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_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the key handle */ + TPM_BOOL isZero; /* contextNonceKey not set yet */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */ + TPM_CONTEXT_BLOB contextBlob; + TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveKeyContext: Ordinal Entry\n"); + TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */ + TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */ + TPM_ContextBlob_Init(&contextBlob); /* freed @3 */ + TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveKeyContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. This command allows saving a loaded key outside the TPM. After creation of the + KeyContextBlob, the TPM automatically releases the internal memory used by that key. The + format of the key context blob is specific to a TPM. + + 2. A TPM protected capability belonging to the TPM that created a key context blob MUST be + the only entity that can interpret the contents of that blob. If a cryptographic technique is + used for this purpose, the level of security provided by that technique SHALL be at least as + secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a cryptographic + technique MUST be generated using the TPM's random number generator. Any symmetric key MUST + be used within the power-on session during which it was created, only. + + 3. A key context blob SHALL enable verification of the integrity of the contents of the blob + by a TPM protected capability. + + 4. A key context blob SHALL enable verification of the session validity of the contents of + the blob by a TPM protected capability. The method SHALL ensure that all key context blobs + are rendered invalid if power to the TPM is interrupted. + */ + /* check if the key handle is valid */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveKeyContext: Handle %08x\n", keyHandle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyHandle); + } + /* use the contextNonceKey to invalidate a blob at power up */ + if (returnCode == TPM_SUCCESS) { + /* If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */ + TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey); + if (isZero) { + /* Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey); + } + } + /* Create internalData by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive + information of the resource is included in internalData. For a key, the sensitive part is + the TPM_STORE_ASYMKEY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_SENSITIVE\n"); + returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData), + tpm_key_handle_entry, + (TPM_STORE_FUNCTION_T)TPM_KeyHandleEntry_Store); + } + if (returnCode == TPM_SUCCESS) { + /* TPM_CONTEXT_SENSITIVE -> contextNonce */ + TPM_Nonce_Copy(contextSensitive.contextNonce, tpm_state->tpm_stclear_data.contextNonceKey); + /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */ + printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_BLOB\n"); + contextBlob.resourceType = TPM_RT_KEY; + contextBlob.handle = keyHandle; + contextBlob.contextCount = 0; + } + /* TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer); + } + /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using + TPM_PERMANENT_DATA -> tpmProof as the secret */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveKeyContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (contextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &contextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the + result in TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData)); + printf("TPM_Process_SaveKeyContext: Encrypting TPM_CONTEXT_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer, + tpm_state->tpm_permanent_data.contextKey); + } + /* serialize TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob); + } + /* invalidate the key handle and delete the key */ + if (returnCode == TPM_SUCCESS) { + /* free the key resources, free the key itself, and remove entry from the key handle entries + list */ + TPM_KeyHandleEntry_Delete(tpm_key_handle_entry); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveKeyContext: 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 keyContextSize and keyContextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */ + TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */ + TPM_ContextBlob_Delete(&contextBlob); /* @3 */ + TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */ + return rcf; +} + +/* 27.2.2 TPM_LoadKeyContext rev 87 + + LoadKeyContext loads a key context blob into the TPM previously retrieved by a SaveKeyContext + call. After successful completion the handle returned by this command can be used to access the + key. +*/ + +TPM_RESULT TPM_Process_LoadKeyContext(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 */ + uint32_t keyContextSize; /* The size of the following key context blob */ + TPM_CONTEXT_BLOB keyContextBlob; /* The key context blob */ + + /* 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 */ + unsigned char *stream; + uint32_t stream_size; + unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */ + uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_KEY_HANDLE_ENTRY *used_key_handle_entry; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + TPM_RESULT getRc; /* is the handle value free */ + TPM_BOOL isSpace; + uint32_t index; /* free space index */ + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE keyHandle; /* The handle assigned to the key after it has been + successfully loaded. */ + + printf("TPM_Process_LoadKeyContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&keyContextBlob); /* freed @1 */ + contextSensitiveBuffer = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */ + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get keyContextSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyContextSize, &command, ¶mSize); + } + /* get keyContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&keyContextBlob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKeyContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. This command allows loading a key context blob into the TPM previously retrieved by a + TPM_SaveKeyContext call. After successful completion the handle returned by this command can + be used to access the key. + + 2. The contents of a key context blob SHALL be discarded unless the contents have passed an + integrity test. This test SHALL (statistically) prove that the contents of the blob are the + same as when the blob was created. + + 3. The contents of a key context blob SHALL be discarded unless the contents have passed a + session validity test. This test SHALL (statistically) prove that the blob was created by + this TPM during this power-on session. + */ + if (returnCode == TPM_SUCCESS) { + if (keyContextBlob.resourceType != TPM_RT_KEY) { + printf("TPM_Process_LoadKeyContext: Error, resourceType %08x should be TPM_RT_KEY\n", + keyContextBlob.resourceType); + returnCode =TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n"); + returnCode = + TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */ + &contextSensitiveBuffer_length, /* length decrypted data */ + keyContextBlob.sensitiveData.buffer, /* encrypted */ + keyContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* deserialize TPM_CONTEXT_SENSITIVE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Creating TPM_CONTEXT_SENSITIVE\n"); + stream = contextSensitiveBuffer; + stream_size = contextSensitiveBuffer_length; + returnCode = TPM_ContextSensitive_Load(&contextSensitive, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Loading TPM_KEY_HANDLE_ENTRY from internalData\n"); + stream = contextSensitive.internalData.buffer; + stream_size = contextSensitive.internalData.size; + returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size); + } + /* check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n"); + returnCode = TPM_Nonce_Compare(tpm_state->tpm_stclear_data.contextNonceKey, + contextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Error comparing contextNonceKey\n"); + returnCode = TPM_BADCONTEXT; + } + } + /* Move decrypted data back to keyContextBlob for integrityDigest check. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&(keyContextBlob.sensitiveData), + contextSensitiveBuffer_length, contextSensitiveBuffer); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking integrityDigest\n"); + /* make a copy of integrityDigest, because it needs to be 0 for the HMAC calculation */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* b. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof + as the HMAC key */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &keyContextBlob, /* structure */ + keyContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* try to use the saved handle value when possible */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking if suggested handle %08x is free\n", + keyContextBlob.handle); + /* check if the key handle is free */ + getRc = TPM_KeyHandleEntries_GetEntry(&used_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyContextBlob.handle); + /* GetEntry TPM_SUCCESS means the handle is already used */ + if (getRc == TPM_SUCCESS) { + keyHandle = 0; /* no suggested handle */ + } + /* not success means that the handle value is not currently used */ + else { + keyHandle = keyContextBlob.handle; + } + } + /* check that there is space in the key handle entries */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking for table space\n"); + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, + tpm_state->tpm_key_handle_entries); + /* if there is no space, return error */ + if (!isSpace) { + printf("TPM_Process_LoadKeyContext: Error, no room in table\n"); + returnCode = TPM_RESOURCES; + } + } + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Adding entry to table\n"); + returnCode = TPM_KeyHandleEntries_AddEntry(&keyHandle, + FALSE, /* keep handle */ + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + key_added = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKeyContext: 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) { + /* return keyHandle */ + returnCode = TPM_Sbuffer_Append32(response, keyHandle); + /* 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextBlob_Delete(&keyContextBlob); /* @1 */ + free(contextSensitiveBuffer); /* @2 */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(tpm_key_handle_entry.key); /* @5 */ + free(tpm_key_handle_entry.key); /* @5 */ + if (key_added) { + /* if there was a failure and a key 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, keyHandle); + } + } + return rcf; +} + +/* 27.2.3 TPM_SaveAuthContext rev 87 + + SaveAuthContext saves a loaded authorization session outside the TPM. After creation of the + authorization context blob, the TPM automatically releases the internal memory used by that + session. The format of the authorization context blob is specific to a TPM. +*/ + +TPM_RESULT TPM_Process_SaveAuthContext(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_AUTHHANDLE authHandle; /* Authorization session which will be kept outside the TPM + */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data; /* session table entry for the handle */ + TPM_BOOL isZero; /* contextNonceSession not set yet */ + TPM_STCLEAR_DATA *v1StClearData = NULL; + uint32_t contextIndex = 0; /* free index in context list */ + uint32_t space; /* free space in context list */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */ + TPM_CONTEXT_BLOB contextBlob; + TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveAuthContext: Ordinal Entry\n"); + TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */ + TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */ + TPM_ContextBlob_Init(&contextBlob); /* freed @3 */ + TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get authHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: authHandle %08x\n", authHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveAuthContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command allows saving a loaded authorization session outside the TPM. After creation of + the authContextBlob, the TPM automatically releases the internal memory used by that + session. The format of the authorization context blob is specific to a TPM. + + A TPM protected capability belonging to the TPM that created an authorization context blob + MUST be the only entity that can interpret the contents of that blob. If a cryptographic + technique is used for this purpose, the level of security provided by that technique SHALL be + at least as secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a + cryptographic technique MUST be generated using the TPM's random number generator. Any + symmetric key MUST be used within the power-on session during which it was created, only. + + An authorization context blob SHALL enable verification of the integrity of the contents of + the blob by a TPM protected capability. + + An authorization context blob SHALL enable verification of the session validity of the + contents of the blob by a TPM protected capability. The method SHALL ensure that all + authorization context blobs are rendered invalid if power to the TPM is interrupted. + */ + /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Handle %08x\n", authHandle); + returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, + v1StClearData->authSessions, + authHandle); + } + if (returnCode == TPM_SUCCESS) { + /* If TPM_STANY_DATA -> contextNonceSession is NULLS */ + TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession); + if (isZero) { + /* Set TPM_STANY_DATA -> contextNonceSession to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession); + } + } + /* Create internalData by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive + information of the resource is included in internalData. For a session, the entire structure + can fit in the sensitive part. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_SENSITIVE\n"); + returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData), + tpm_auth_session_data, + (TPM_STORE_FUNCTION_T)TPM_AuthSessionData_Store); + } + if (returnCode == TPM_SUCCESS) { + } + if (returnCode == TPM_SUCCESS) { + /* TPM_CONTEXT_SENSITIVE -> contextNonce */ + TPM_Nonce_Copy(contextSensitive.contextNonce, v1StClearData->contextNonceSession); + /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */ + printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_BLOB\n"); + contextBlob.resourceType = TPM_RT_AUTH; + contextBlob.handle = authHandle; + TPM_Digest_Init(contextBlob.integrityDigest); + } + /* TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Processing session context count\n"); + /* a. If V1 -> contextCount > 2^32-2 then */ + if (v1StClearData->contextCount > 0xfffffffe) { + /* i. Return with TPM_TOOMANYCONTEXTS */ + printf("TPM_Process_SaveAuthContext: Error, too many contexts\n"); + returnCode = TPM_TOOMANYCONTEXTS; + } + } + /* b. Else */ + if (returnCode == TPM_SUCCESS) { + /* i. Increment V1 -> contextCount by 1 */ + v1StClearData->contextCount++; + /* ii. Validate that the TPM can still manage the new count value */ + /* (1) If the distance between the oldest saved context and the contextCount is + too large return TPM_CONTEXT_GAP */ + /* Since contextCount is uint32_t, this is not applicable here. From email: Does the + TPM have the ability to keep track of the context delta. It is possible to keep + track of things with just a byte or so internally, if this is done a gap of + greater than 2^16 or so might be too large, hence the context gap message */ + } + /* iii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not + found exit with TPM_NOCONTEXTSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList); + if (space == 0) { + printf("TPM_Process_SaveAuthContext: Error, no space in context list\n"); + returnCode = TPM_NOCONTEXTSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */ + v1StClearData->contextList[contextIndex] = v1StClearData->contextCount; + /* v. Set B1 -> contextCount to V1 -> contextCount */ + contextBlob.contextCount = v1StClearData->contextCount; + } + /* c. The TPM MUST invalidate all information regarding the resource except for information + needed for reloading */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, authHandle); + } + /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using + TPM_PERMANENT_DATA -> tpmProof as the secret */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveAuthContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (contextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &contextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the + result in TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData)); + printf("TPM_Process_SaveAuthContext: Encrypting TPM_CONTEXT_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer, + tpm_state->tpm_permanent_data.contextKey); + } + /* serialize TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveAuthContext: 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 authContextSize and authContextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */ + TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */ + TPM_ContextBlob_Delete(&contextBlob); /* @3 */ + TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */ + return rcf; +} + +/* 27.2.4 TPM_LoadAuthContext rev 106 + + LoadAuthContext loads an authorization context blob into the TPM previously retrieved by a + SaveAuthContext call. After successful completion, the handle returned by this command can be used + to access the authorization session. +*/ + +TPM_RESULT TPM_Process_LoadAuthContext(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 */ + uint32_t authContextSize; /* The size of the following auth context blob */ + TPM_CONTEXT_BLOB authContextBlob; /* The auth context blob */ + + /* 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 */ + unsigned char *stream; + uint32_t stream_size; + unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */ + uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_AUTH_SESSION_DATA tpm_auth_session_data; + TPM_AUTH_SESSION_DATA *used_auth_session_data; + TPM_RESULT getRc; /* is the handle value free */ + TPM_BOOL isSpace; + uint32_t index; /* free space index */ + TPM_BOOL auth_session_added = FALSE; /* session key has been added to handle list */ + TPM_STCLEAR_DATA *v1StClearData = NULL; + uint32_t contextIndex; + TPM_DIGEST entityDigest; /* digest of the entity used to set up the + OSAP or DSAP session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE authHandle; /* The handle assigned to the authorization session after it + has been successfully loaded. */ + + printf("TPM_Process_LoadAuthContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&authContextBlob); /* freed @1 */ + contextSensitiveBuffer = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */ + TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get authContextSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authContextSize, &command, ¶mSize); + } + /* get authContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&authContextBlob, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: handle %08x\n", authContextBlob.handle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadAuthContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command allows loading an authorization context blob into the TPM previously retrieved + by a TPM_SaveAuthContext call. After successful completion, the handle returned by this + command can be used to access the authorization session. + + The contents of an authorization context blob SHALL be discarded unless the contents have + passed an integrity test. This test SHALL (statistically) prove that the contents of the blob + are the same as when the blob was created. + + The contents of an authorization context blob SHALL be discarded unless the contents have + passed a session validity test. This test SHALL (statistically) prove that the blob was + created by this TPM during this power-on session. + + For an OSAP authorization context blob referring to a key, verify that the key linked to this + session is resident in the TPM. + */ + if (returnCode == TPM_SUCCESS) { + /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + v1StClearData = &(tpm_state->tpm_stclear_data); + if (authContextBlob.resourceType != TPM_RT_AUTH) { + printf("TPM_Process_LoadAuthContext: Error, resourceType %08x should be TPM_RT_AUTH\n", + authContextBlob.resourceType); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n"); + returnCode = + TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */ + &contextSensitiveBuffer_length, /* length decrypted data */ + authContextBlob.sensitiveData.buffer, /* encrypted */ + authContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* deserialize TPM_CONTEXT_SENSITIVE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Creating TPM_CONTEXT_SENSITIVE\n"); + stream = contextSensitiveBuffer; + stream_size = contextSensitiveBuffer_length; + returnCode = TPM_ContextSensitive_Load(&contextSensitive, + &stream, + &stream_size); + } + /* Parse the TPM_CONTEXT_SENSITIVE -> internalData to TPM_AUTH_SESSION_DATA */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Loading TPM_AUTH_SESSION_DATA from internalData\n"); + stream = contextSensitive.internalData.buffer; + stream_size = contextSensitive.internalData.size; + returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size); + } + /* check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: protocolID %04x entityTypeByte %02x\n", + tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte); + printf("TPM_Process_LoadAuthContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n"); + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession, + contextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Error comparing contextNonceSession\n"); + returnCode = TPM_BADCONTEXT; + } + } + if (returnCode == TPM_SUCCESS) { + if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) || + (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) { + /* check that the entity is loaded, and that the entity's digest equals that of the OSAP + or DSAP session */ + switch (tpm_auth_session_data.entityTypeByte) { + case TPM_ET_OWNER: + printf("TPM_Process_LoadAuthContext: Owner OSAP/DSAP session\n"); + /* check for owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state, entityDigest); + } + /* compare entity digest */ + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + break; + case TPM_ET_SRK: + printf("TPM_Process_LoadAuthContext: SRK OSAP/DSAP session\n"); + /* check for SRK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state, entityDigest); + } + /* compare entity digest */ + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + break; + case TPM_ET_KEYHANDLE: + printf("TPM_Process_LoadAuthContext: Key OSAP/DSAP session\n"); + /* for keys */ + returnCode = + TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state, + tpm_auth_session_data.entityDigest); + break; + case TPM_ET_COUNTER: + printf("TPM_Process_LoadAuthContext: Counter OSAP/DSAP session\n"); +#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no counter */ + returnCode = + TPM_LoadContext_CheckCounterLoaded(tpm_state, + entityHandle, + entityDigest); +#endif + break; + case TPM_ET_NV: + printf("TPM_Process_LoadAuthContext: NV OSAP/DSAP session\n"); +#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no NV space */ + returnCode = + TPM_LoadContext_CheckNvLoaded(tpm_state, + entityHandle, + entityDigest); +#endif + break; + default: + printf("TPM_Process_LoadAuthContext: Error, invalid session entityType %02x\n", + tpm_auth_session_data.entityTypeByte); + returnCode = TPM_WRONG_ENTITYTYPE; + break; + } + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking integrityDigest\n"); + /* b. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */ + returnCode = TPM_SizedBuffer_Set(&(authContextBlob.sensitiveData), + contextSensitiveBuffer_length, contextSensitiveBuffer); + /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof + as the HMAC key */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &authContextBlob, /* structure */ + authContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* try to use the saved handle value when possible */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking if suggested handle %08x is free\n", + authContextBlob.handle); + /* check if the auth handle is free */ + getRc = TPM_AuthSessions_GetEntry(&used_auth_session_data, + tpm_state->tpm_stclear_data.authSessions, + authContextBlob.handle); + /* GetEntry TPM_SUCCESS means the handle is already used */ + if (getRc == TPM_SUCCESS) { + authHandle = 0; /* no suggested handle */ + } + /* not success means that the handle value is not currently used */ + else { + authHandle = authContextBlob.handle; + } + } + /* check that there is space in the authorization handle entries */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking for table space\n"); + TPM_AuthSessions_IsSpace(&isSpace, &index, + tpm_state->tpm_stclear_data.authSessions); + /* if there is no space, return error */ + if (!isSpace) { + printf("TPM_Process_LoadAuthContext: Error, no room in table\n"); + TPM_AuthSessions_Trace(tpm_state->tpm_stclear_data.authSessions); + returnCode = TPM_RESOURCES; + } + } + /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 -> + TPM_CONTEXT_BLOB -> contextCount */ + /* b. If not found then return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking contextCount\n"); + returnCode = TPM_ContextList_GetEntry(&contextIndex, + v1StClearData->contextList, + authContextBlob.contextCount); + } + /* c. Set V1 -> contextList[contextIndex] to 0 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData->contextList[contextIndex] = 0; + } + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_AddEntry(&authHandle, /* input/output */ + FALSE, /* keepHandle */ + v1StClearData->authSessions, + &tpm_auth_session_data); + auth_session_added = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadAuthContext: 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) { + /* return authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + /* 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextBlob_Delete(&authContextBlob); /* @1 */ + free(contextSensitiveBuffer); /* @2 */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */ + TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + if (auth_session_added) { + TPM_AuthSessionData_Delete(&tpm_auth_session_data); + } + } + return rcf; +} diff --git a/src/tpm12/tpm_session.h b/src/tpm12/tpm_session.h new file mode 100644 index 0000000..a7c9c6d --- /dev/null +++ b/src/tpm12/tpm_session.h @@ -0,0 +1,276 @@ +/********************************************************************************/ +/* */ +/* TPM Sessions Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_session.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_SESSION_H +#define TPM_SESSION_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + TPM_AUTH_SESSION_DATA (the entire array) +*/ + +void TPM_AuthSessions_Init(TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_Load(TPM_AUTH_SESSION_DATA *authSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_AuthSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_Delete(TPM_AUTH_SESSION_DATA *authSessions); + + +void TPM_AuthSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_Trace(TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_GetSpace(uint32_t *space, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_GetNewHandle(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTHHANDLE *authHandle, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_GetEntry(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle); +TPM_RESULT TPM_AuthSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +TPM_RESULT TPM_AuthSessions_GetData(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_SECRET **hmacKey, + tpm_state_t *tpm_state, + TPM_AUTHHANDLE authHandle, + TPM_PROTOCOL_ID protocolID, + TPM_ENT_TYPE entityType, + TPM_COMMAND_CODE ordinal, + TPM_KEY *tpmKey, + TPM_SECRET *entityAuth, + TPM_DIGEST entityDigest); + +TPM_RESULT TPM_AuthSessions_TerminateHandle(TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle); +void TPM_AuthSessions_TerminateEntity(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_ENT_TYPE entityType, + TPM_DIGEST *entityDigest); +void TPM_AuthSessions_TerminatexSAP(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions); + +/* + TPM_AUTH_SESSION_DATA (one element of the array) +*/ + + +void TPM_AuthSessionData_Init(TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +TPM_RESULT TPM_AuthSessionData_Load(TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_AuthSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +void TPM_AuthSessionData_Delete(TPM_AUTH_SESSION_DATA *tpm_auth_session_data); + + +void TPM_AuthSessionData_Copy(TPM_AUTH_SESSION_DATA *dest_auth_session_data, + TPM_HANDLE tpm_handle, + TPM_AUTH_SESSION_DATA *src_auth_session_data); +TPM_RESULT TPM_AuthSessionData_GetDelegatePublic(TPM_DELEGATE_PUBLIC **delegatePublic, + TPM_AUTH_SESSION_DATA *auth_session_data); +TPM_RESULT TPM_AuthSessionData_CheckEncScheme(TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_BOOL FIPS); +TPM_RESULT TPM_AuthSessionData_Decrypt(TPM_DIGEST a1Even, + TPM_DIGEST a1Odd, + TPM_ENCAUTH encAuthEven, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_ENCAUTH encAuthOdd, + TPM_BOOL odd); + +/* + Context List +*/ + +void TPM_ContextList_Init(uint32_t *contextList); +TPM_RESULT TPM_ContextList_Load(uint32_t *contextList, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextList_Store(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList); + +TPM_RESULT TPM_ContextList_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList); +void TPM_ContextList_GetSpace(uint32_t *space, + uint32_t *entry, + const uint32_t *contextList); +TPM_RESULT TPM_ContextList_GetEntry(uint32_t *entry, + const uint32_t *contextList, + uint32_t value); + +/* + TPM_CONTEXT_BLOB +*/ + +void TPM_ContextBlob_Init(TPM_CONTEXT_BLOB *tpm_context_blob); +TPM_RESULT TPM_ContextBlob_Load(TPM_CONTEXT_BLOB *tpm_context_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_BLOB *tpm_context_blob); +void TPM_ContextBlob_Delete(TPM_CONTEXT_BLOB *tpm_context_blob); + +/* + TPM_CONTEXT_SENSITIVE +*/ + +void TPM_ContextSensitive_Init(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); +TPM_RESULT TPM_ContextSensitive_Load(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); +void TPM_ContextSensitive_Delete(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_OIAP(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 TPM_Process_OSAP(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 TPM_Process_DSAP(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 TPM_Process_SetOwnerPointer(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 TPM_Process_TerminateHandle(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 TPM_Process_FlushSpecific(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 TPM_Process_SaveContext(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 TPM_Process_LoadContext(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 TPM_Process_KeyControlOwner(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 TPM_Process_SaveKeyContext(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 TPM_Process_LoadKeyContext(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 TPM_Process_SaveAuthContext(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 TPM_Process_LoadAuthContext(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); + + + + + + +#endif diff --git a/src/tpm12/tpm_sizedbuffer.c b/src/tpm12/tpm_sizedbuffer.c new file mode 100644 index 0000000..046ad43 --- /dev/null +++ b/src/tpm12/tpm_sizedbuffer.c @@ -0,0 +1,374 @@ +/********************************************************************************/ +/* */ +/* TPM Sized Buffer Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_sizedbuffer.c 4071 2010-04-29 19:26:45Z 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 <stdlib.h> +#include <string.h> + +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_sizedbuffer.h" + +void TPM_SizedBuffer_Init(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + tpm_sized_buffer->size = 0; + tpm_sized_buffer->buffer = NULL; + return; +} + +/* TPM_SizedBuffer_Load() allocates and sets a sized buffer from a stream. A sized buffer structure + has two members: + + - 4 bytes size + - pointer to array of 'size' + + This structure is typically a cast from a subset of a larger TPM structure. Two members - a 4 + bytes size followed by a 4 bytes pointer to the data is a common TPM structure idiom. + + This function correctly handles a 'size' of 0. + + Call TPM_SizedBuffer_Init() before first use + Call TPM_SizedBuffer_Delete() after use +*/ + +TPM_RESULT TPM_SizedBuffer_Load(TPM_SIZED_BUFFER *tpm_sized_buffer, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Load:\n"); + if (rc == 0) { + rc = TPM_Load32(&(tpm_sized_buffer->size), stream, stream_size); + } + /* if the size is not 0 */ + if ((rc == 0) && (tpm_sized_buffer->size > 0)) { + /* allocate memory for the buffer */ + if (rc == 0) { + rc = TPM_Malloc(&(tpm_sized_buffer->buffer), tpm_sized_buffer->size); + } + /* copy the buffer */ + if (rc == 0) { + rc = TPM_Loadn(tpm_sized_buffer->buffer, tpm_sized_buffer->size, stream, stream_size); + } + } + return rc; +} + +/* TPM_SizedBuffer_Set() reallocs a sized buffer and copies 'size' bytes of 'data' into it. + + If the sized buffer already has data, the buffer is realloc'ed. + + This function correctly handles a 'size' of 0. + + Call TPM_SizedBuffer_Delete() to free the buffer +*/ + +TPM_RESULT TPM_SizedBuffer_Set(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size, + const unsigned char *data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Set:\n"); + /* allocate memory for the buffer, and copy the buffer */ + if (rc == 0) { + if (size > 0) { + rc = TPM_Realloc(&(tpm_sized_buffer->buffer), + size); + if (rc == 0) { + tpm_sized_buffer->size = size; + memcpy(tpm_sized_buffer->buffer, data, size); + } + } + /* if size is zero */ + else { + TPM_SizedBuffer_Delete(tpm_sized_buffer); + } + } + return rc; +} + +/* TPM_SizedBuffer_SetFromStore() reallocs a sized buffer and copies 'sbuffer" data into it. + + This function correctly handles an 'sbuffer' of 0 length. + */ + +TPM_RESULT TPM_SizedBuffer_SetFromStore(TPM_SIZED_BUFFER *tpm_sized_buffer, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *data; + uint32_t size; + + if (rc == 0) { + /* get the stream and its size from the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &data, &size); + rc = TPM_SizedBuffer_Set(tpm_sized_buffer, size, data); + } + return rc; +} + +/* TPM_SizedBuffer_SetStructure() serializes the structure 'tpmStructure' using the function + 'storeFunction', storing the result in a TPM_SIZED_BUFFER. +*/ + +TPM_RESULT TPM_SizedBuffer_SetStructure(TPM_SIZED_BUFFER *tpm_sized_buffer, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_SizedBuffer_SetStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the structure */ + if (rc == 0) { + if (tpmStructure != NULL) { + rc = storeFunction(&sbuffer, tpmStructure); + } + } + /* copy to TPM_SIZED_BUFFER */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(tpm_sized_buffer, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +TPM_RESULT TPM_SizedBuffer_Copy(TPM_SIZED_BUFFER *tpm_sized_buffer_dest, + TPM_SIZED_BUFFER *tpm_sized_buffer_src) +{ + TPM_RESULT rc = 0; + rc = TPM_SizedBuffer_Set(tpm_sized_buffer_dest, + tpm_sized_buffer_src->size, + tpm_sized_buffer_src->buffer); + return rc; +} + + +/* TPM_SizedBuffer_Store() serializes a TPM_SIZED_BUFFER into a TPM_STORE_BUFFER + */ + +TPM_RESULT TPM_SizedBuffer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Store:\n"); + /* append the size */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_sized_buffer->size); + } + /* append the data */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_sized_buffer->buffer, tpm_sized_buffer->size); + } + return rc; +} + +void TPM_SizedBuffer_Delete(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + printf(" TPM_SizedBuffer_Delete:\n"); + if (tpm_sized_buffer != NULL) { + free(tpm_sized_buffer->buffer); + TPM_SizedBuffer_Init(tpm_sized_buffer); + } + return; +} + +/* TPM_SizedBuffer_Allocate() allocates 'size' bytes of memory and sets the TPM_SIZED_BUFFER + members. + + The buffer data is not initialized. +*/ + +TPM_RESULT TPM_SizedBuffer_Allocate(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Allocate: Size %u\n", size); + tpm_sized_buffer->size = size; + rc = TPM_Malloc(&(tpm_sized_buffer->buffer), size); + return rc; +} + +/* TPM_SizedBuffer_GetBool() converts from a TPM_SIZED_BUFFER to a TPM_BOOL. + + If the size does not indicate a TPM_BOOL, an error is returned. +*/ + +TPM_RESULT TPM_SizedBuffer_GetBool(TPM_BOOL *tpm_bool, + TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + + if (tpm_sized_buffer->size == sizeof(TPM_BOOL)) { + *tpm_bool = *(TPM_BOOL *)tpm_sized_buffer->buffer; + printf(" TPM_SizedBuffer_GetBool: bool %02x\n", *tpm_bool); + } + else { + printf("TPM_SizedBuffer_GetBool: Error, buffer size %08x is not a BOOL\n", + tpm_sized_buffer->size); + rc = TPM_BAD_PARAMETER; + } + return rc; +} + +/* TPM_SizedBuffer_GetUint32() converts from a TPM_SIZED_BUFFER to a uint32_t. + + If the size does not indicate a uint32_t, an error is returned. +*/ + +TPM_RESULT TPM_SizedBuffer_GetUint32(uint32_t *uint32, + TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + if (rc == 0) { + if (tpm_sized_buffer->size != sizeof(uint32_t)) { + printf("TPM_GetUint32: Error, buffer size %08x is not a uint32_t\n", + tpm_sized_buffer->size); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + rc = TPM_Load32(uint32, &stream, &stream_size); + } + return rc; +} + +/* TPM_SizedBuffer_Append32() appends a uint32_t to a TPM_SIZED_BUFFER + +*/ + +TPM_RESULT TPM_SizedBuffer_Append32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Append32: Current size %u uint32 %08x\n", + tpm_sized_buffer->size, uint32); + /* allocate space for another uint32_t */ + if (rc == 0) { + rc = TPM_Realloc(&(tpm_sized_buffer->buffer), + tpm_sized_buffer->size + sizeof(uint32_t)); + } + if (rc == 0) { + uint32_t ndata = htonl(uint32); /* convert to network byte order */ + memcpy(tpm_sized_buffer->buffer + tpm_sized_buffer->size, /* append at end */ + (char *)&ndata, /* cast safe after conversion */ + sizeof(uint32_t)); + tpm_sized_buffer->size += sizeof(uint32_t); + } + return rc; +} + +/* TPM_SizedBuffer_Remove32() removes the uint32_t with value from a TPM_SIZED_BUFFER + +*/ + +TPM_RESULT TPM_SizedBuffer_Remove32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint32_t bufferValue; + TPM_BOOL found = FALSE; + unsigned char *from; + unsigned char *to; + + printf(" TPM_SizedBuffer_Remove32: Current size %u uint32 %08x\n", + tpm_sized_buffer->size, uint32); + + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + + /* search for the uint32 */ + while ((rc == 0) && (stream_size != 0) && !found) { + /* get the next value */ + if (rc == 0) { + rc = TPM_Load32(&bufferValue, &stream, &stream_size); + } + /* if the value is the one to be removed */ + if (rc == 0) { + if (bufferValue == uint32) { + found = TRUE; + /* shift the reset of the buffer down by a uint32_t */ + for (from = stream, to = (stream - sizeof(uint32_t)) ; + /* go to the end of the buffer */ + from < (tpm_sized_buffer->buffer + tpm_sized_buffer->size) ; + from++, to++) { + *to = *from; + } + /* adjust the size */ + tpm_sized_buffer->size -= sizeof(uint32_t); + } + } + } + if (!found) { + printf("TPM_SizedBuffer_Remove32: Error, value not found\n"); + rc = TPM_BAD_HANDLE; + } + return rc; +} + +/* TPM_SizedBuffer_Zero() overwrites all data in the buffer with zeros + + */ + +void TPM_SizedBuffer_Zero(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + printf(" TPM_SizedBuffer_Zero:\n"); + if (tpm_sized_buffer->buffer != NULL) { + memset(tpm_sized_buffer->buffer, 0, tpm_sized_buffer->size); + } + return; +} diff --git a/src/tpm12/tpm_sizedbuffer.h b/src/tpm12/tpm_sizedbuffer.h new file mode 100644 index 0000000..a92c3e9 --- /dev/null +++ b/src/tpm12/tpm_sizedbuffer.h @@ -0,0 +1,75 @@ +/********************************************************************************/ +/* */ +/* TPM Sized Buffer Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_sizedbuffer.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_SIZEDBUFFER_H +#define TPM_SIZEDBUFFER_H + +#include "tpm_digest.h" +#include "tpm_store.h" + +void TPM_SizedBuffer_Init(TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Load(TPM_SIZED_BUFFER *tpm_sized_buffer, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SizedBuffer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Set(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size, + const unsigned char *data); +TPM_RESULT TPM_SizedBuffer_SetFromStore(TPM_SIZED_BUFFER *tpm_sized_buffer, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_SizedBuffer_SetStructure(TPM_SIZED_BUFFER *tpm_sized_buffer, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_SizedBuffer_Copy(TPM_SIZED_BUFFER *tpm_sized_buffer_dest, + TPM_SIZED_BUFFER *tpm_sized_buffer_src); +void TPM_SizedBuffer_Delete(TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Allocate(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size); +TPM_RESULT TPM_SizedBuffer_GetBool(TPM_BOOL *tpm_bool, + TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_GetUint32(uint32_t *uint32, + TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Append32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32); +TPM_RESULT TPM_SizedBuffer_Remove32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32); +void TPM_SizedBuffer_Zero(TPM_SIZED_BUFFER *tpm_sized_buffer); + +#endif diff --git a/src/tpm12/tpm_startup.c b/src/tpm12/tpm_startup.c new file mode 100644 index 0000000..25b9e08 --- /dev/null +++ b/src/tpm12/tpm_startup.c @@ -0,0 +1,1446 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Startup and State */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_startup.c 4533 2011-03-30 19:50:41Z 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 <stdlib.h> + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_constants.h" +#include "tpm_commands.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_digest.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvfilename.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_session.h" + +#include "tpm_startup.h" + +/* + Save State +*/ + +/* TPM_SaveState_Load() restores the TPM state from a stream created by TPM_SaveState_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_SaveState_Load:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Load: Loading PCR's\n"); + } + /* 1. Store PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Load() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done at TPM_StclearData_Load() */ + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_SaveState_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_SaveState_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_SaveState_Store() stores the TPM state to a stream that can be restored through + TPM_SaveState_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_SaveState_Store:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Store: Storing PCR's\n"); + } + /* NOTE: Actions from TPM_SaveState */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Store() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* NOTE Done naturally because this function is called between input and output audit. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE This implementation saves all keys. Owner evict keys are not saved in the state blob, + as they are already saved in the file system */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done by TPM_StclearData_Store() */ + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_SaveState_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_SaveState_IsSaveKey() determines which keys are saved as part of the saved state. + + According to Ryan, all keys must be saved for this to be of use. +*/ + +void TPM_SaveState_IsSaveKey(TPM_BOOL *save, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + *save = FALSE; + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Owner evict keys are not saved in the state blob, as they are already saved in the file + system */ + if (!(tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + *save = TRUE; + } + else { + *save = FALSE; + } + if (*save) { + printf(" TPM_SaveState_IsSaveKey: Save key handle %08x\n", tpm_key_handle_entry->handle); + } + return; +} + +/* TPM_SaveState_NVLoad() deserializes the saved state data from the NV file TPM_SAVESTATE_NAME + + 0 on success. + Returns TPM_RETRY on non-existent file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_SaveState_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_SaveState_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + } + /* deserialize from stream */ + if (rc == 0) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_SaveState_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_SaveState_NVLoad: Error (fatal) loading deserializing saved state\n"); + rc = TPM_FAIL; + } + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVStore() serializes saved state data and stores it in the NV file + TPM_SAVESTATE_NAME +*/ + +TPM_RESULT TPM_SaveState_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_SaveState_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_SaveState_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_SaveState_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_SAVESTATE_SPACE) { + printf("TPM_SaveState_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_SAVESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + tpm_state->tpm_stany_flags.stateSaved = TRUE; /* mark the state as stored */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVDelete() deletes the NV file + + If mustExist is TRUE, returns an error if the file does not exist. + If mustExist is FALSE, returns success if the file does not exist. +*/ + +TPM_RESULT TPM_SaveState_NVDelete(tpm_state_t *tpm_state, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SaveState_NVDelete:\n"); + if (rc == 0) { + /* remove the saved state */ + rc = TPM_NVRAM_DeleteName(tpm_state->tpm_number, + TPM_SAVESTATE_NAME, + mustExist); + tpm_state->tpm_stany_flags.stateSaved = FALSE; /* mark the state as deleted */ + } + return rc; +} + +/* Volatile state includes all the tpm_state structure volatile members. It is a superset of Saved + state, used when the entire TPM state must be saved and restored +*/ + +/* TPM_VolatileAll_Load() restores the TPM state from a stream created by TPM_VolatileAll_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_VolatileAll_Load:\n"); + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_VSTATE_V1, stream, stream_size); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Load(stream, stream_size); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STCLEAR_FLAGS_V1, stream, stream_size); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Load(&(tpm_state->tpm_stany_flags), stream, stream_size); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Load(&(tpm_state->tpm_stany_data), stream, stream_size); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading SHA ordinal context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context), stream, stream_size); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading TIS context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context_tis), stream, stream_size); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->transportHandle), stream, stream_size); + } + /* testState */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->testState), stream, stream_size); + } + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_VolatileAll_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_VolatileAll_Store() stores the TPM state to a stream that can be restored through + TPM_VolatileAll_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_VolatileAll_Store:\n"); + /* overall format tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_VSTATE_V1); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Store(sbuffer); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_FLAGS_V1); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Store(sbuffer, &(tpm_state->tpm_stany_flags)); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Store(sbuffer, &(tpm_state->tpm_stany_data)); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing SHA ordinal context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing TIS context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context_tis); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->transportHandle); + } + /* testState */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->testState); + } + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_VolatileAll_NVLoad() deserializes the entire volatile state data from the NV file + TPM_VOLATILESTATE_NAME. + + If the file does not exist (a normal startup), returns success. + + 0 on success or non-existent file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_VolatileAll_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_VolatileAll_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + /* if the file does not exist, leave the volatile state initial values */ + if (rc == TPM_RETRY) { + done = TRUE; + rc = 0; + } + else if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading %s\n", TPM_VOLATILESTATE_NAME); + rc = TPM_FAIL; + } + } + /* deserialize from stream */ + if ((rc == 0) && !done) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_VolatileAll_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading deserializing state\n"); + rc = TPM_FAIL; + } + } + if (rc != 0) { + printf(" TPM_VolatileAll_NVLoad: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_VolatileAll_NVStore() serializes the entire volatile state data and stores it in the NV file + TPM_VOLATILESTATE_NAME +*/ + +TPM_RESULT TPM_VolatileAll_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_VolatileAll_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_VolatileAll_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_VOLATILESTATE_SPACE) { + printf("TPM_VolatileAll_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_VOLATILESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Compiled in TPM Parameters +*/ + +TPM_RESULT TPM_Parameters_Load(unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Load:\n"); + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TPM_PARAMETERS_V1, + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MAJOR, "TPM_MAJOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MINOR, "TPM_MINOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_PCCLIENT, "TPM_PCCLIENT", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_PCR, "TPM_NUM_PCR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_RSA_KEY_LENGTH_MAX, "TPM_RSA_KEY_LENGTH_MAX", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_KEY_HANDLES, "TPM_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_OWNER_EVICT_KEY_HANDLES, "TPM_OWNER_EVICT_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + "TPM_NUM_FAMILY_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, + "TPM_NUM_DELEGATE_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_AUTH_SESSIONS, "TPM_MIN_AUTH_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_TRANS_SESSIONS, "TPM_MIN_TRANS_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_DAA_SESSIONS, "TPM_MIN_DAA_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_COUNTERS, "TPM_MIN_COUNTERS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_SESSION_LIST, "TPM_MIN_SESSION_LIST", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check32(TPM_MAX_NV_SPACE, "TPM_MAX_NV_SPACE", + stream, stream_size); + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check8(uint8_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint8_t tmp8; + + if (rc == 0) { + rc = TPM_Load8(&tmp8, stream, stream_size); + if (tmp8 != expected) { + printf("TPM_Parameters_Check8: Error (fatal) %s received %u expect %u\n", + parameter, tmp8, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check16(uint16_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t tmp16; + + if (rc == 0) { + rc = TPM_Load16(&tmp16, stream, stream_size); + if (tmp16 != expected) { + printf("TPM_Parameters_Check16: Error (fatal) %s received %u expect %u\n", + parameter, tmp16, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check32(uint32_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t tmp32; + + if (rc == 0) { + rc = TPM_Load32(&tmp32, stream, stream_size); + if (tmp32 != expected) { + printf("TPM_Parameters_Check32: Error (fatal) %s received %u expect %u\n", + parameter, tmp32, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Store(TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TPM_PARAMETERS_V1); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MAJOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MINOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_PCCLIENT); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_PCR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_RSA_KEY_LENGTH_MAX); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_OWNER_EVICT_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_AUTH_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_TRANS_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_DAA_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_COUNTERS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_SESSION_LIST); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, TPM_MAX_NV_SPACE); + } + return rc; +} + + +/* 27.5 TPM_Reset rev 105 + + Releases all resources associated with existing authorization sessions. This is useful if a TSS + driver has lost track of the state in the TPM. + + This is a deprecated command in V1.2. This command in 1.1 only referenced authorization sessions + and is not upgraded to affect any other TPM entity in 1.2 +*/ + +TPM_RESULT TPM_Process_Reset(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 */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Reset: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Reset: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM invalidates all resources allocated to authorization sessions as per version 1.1 + extant in the TPM */ + /* a. This includes structures created by TPM_SaveAuthContext and TPM_SaveKeyContext */ + /* b.The TPM MUST invalidate OSAP sessions */ + /* c.The TPM MAY invalidate DSAP sessions */ + /* d. The TPM MUST NOT invalidate structures created by TPM_SaveContext */ + if (returnCode == TPM_SUCCESS) { + TPM_StclearData_AuthSessionDelete(&(tpm_state->tpm_stclear_data)); + } + /* 2. The TPM does not reset any PCR or DIR values. */ + /* 3. The TPM does not reset any flags in the TPM_STCLEAR_FLAGS structure. */ + /* 4. The TPM does not reset or invalidate any keys */ + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Reset: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + 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 */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 3.2 TPM_Startup rev 101 + + TPM_Startup is always preceded by TPM_Init, which is the physical indication (a system-wide + reset) that TPM initialization is necessary. + + There are many events on a platform that can cause a reset and the response to these events can + require different operations to occur on the TPM. The mere reset indication does not contain + sufficient information to inform the TPM as to what type of reset is occurring. Additional + information known by the platform initialization code needs transmitting to the TPM. The + TPM_Startup command provides the mechanism to transmit the information. + + The TPM can startup in three different modes: + + A "clear" start where all variables go back to their default or non-volatile set state + + A "save" start where the TPM recovers appropriate information and restores various values based + on a prior TPM_SaveState. This recovery requires an invocation of TPM_Init to be successful. + + A failing "save" start must shut down the TPM. The CRTM cannot leave the TPM in a state where an + untrusted upper software layer could issue a "clear" and then extend PCR's and thus mimic the + CRTM. + + A "deactivated" start where the TPM turns itself off and requires another TPM_Init before the TPM + will execute in a fully operational state. The TPM can startup in three different modes: +*/ + +TPM_RESULT TPM_Process_Startup(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + TPM_RESULT returnCode1 = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_STARTUP_TYPE startupType; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Startup: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get startupType parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&startupType, &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 tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Startup: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* TPM_CheckState() can check for the normal case where postInitialise TRUE is an error. This + is the only command where FALSE is the error. */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STANY_FLAGS -> postInitialise is FALSE, */ + if (!(tpm_state->tpm_stany_flags.postInitialise)) { + /* a. Then the TPM MUST return TPM_INVALID_POSTINIT, and exit this capability */ + printf("TPM_Process_Startup: Error, postInitialise is FALSE\n"); + returnCode = TPM_INVALID_POSTINIT; + } + } + if (returnCode == TPM_SUCCESS) { + /* 1. If the TPM is in failure mode */ + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + /* a. TPM_STANY_FLAGS -> postInitialize is still set to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + printf("TPM_Process_Startup: Error, shutdown is TRUE\n"); + /* b. The TPM returns TPM_FAILEDSELFTEST */ + returnCode = TPM_FAILEDSELFTEST; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + switch (startupType) { + case TPM_ST_CLEAR: /* The TPM is starting up from a clean state */ + returnCode = TPM_Startup_Clear(tpm_state); + break; + case TPM_ST_STATE: /* The TPM is starting up from a saved state */ + returnCode = TPM_Startup_State(tpm_state); + break; + case TPM_ST_DEACTIVATED: /* The TPM is to startup and set the deactivated flag to + TRUE */ + returnCode = TPM_Startup_Deactivated(tpm_state); + break; + default: + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + if (returnCode == TPM_SUCCESS) { + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + } + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode1 = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not + exist. */ + if (returnCode == TPM_SUCCESS) { /* previous error takes precedence */ + returnCode = returnCode1; + } + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Startup: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + 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 */ + } + /* 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); + } + return rcf; +} + +/* 3.2 TPM_Startup(TPM_ST_CLEAR) rev 99 +*/ + +TPM_RESULT TPM_Startup_Clear(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Clear:\n"); + /* 2. If stType = TPM_ST_CLEAR */ + if (returnCode == TPM_SUCCESS) { + /* a. Ensure that sessions associated with resources TPM_RT_CONTEXT, TPM_RT_AUTH, + TPM_RT_DAA_TPM, and TPM_RT_TRANS are invalidated */ + /* NOTE TPM_RT_CONTEXT - + contextNonceKey cleared by TPM_Global_Init() -> TPM_StanyData_Init() + contextNonceSession cleared by TPM_Global_Init() -> TPM_StanyData_Init() + */ + /* NOTE TPM_RT_AUTH - TPM_AuthSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init() */ + /* TPM_RT_TRANS - TPM_TransportSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* TPM_RT_DAA_TPM - TPM_DaaSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* b. Reset PCR values to each correct default value */ + /* i. pcrReset is FALSE, set to 0x00..00 */ + /* ii. pcrReset is TRUE, set to 0xFF..FF */ + /* NOTE done by TPM_MainInit() -> TPM_Global_Init() */ + /* c. Set the following TPM_STCLEAR_FLAGS to their default state + i. PhysicalPresence + ii. PhysicalPresenceLock + iii. disableForceClear + */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* d. The TPM MAY initialize auditDigest to all zeros + i. If not initialized to all zeros the TPM SHALL ensure that auditDigest contains a valid + value + ii. If initialization fails the TPM SHALL set auditDigest to all zeros and SHALL set the + internal TPM state so that the TPM returns TPM_FAILEDSELFTEST to all subsequent + commands. + */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* e. The TPM SHALL set TPM_STCLEAR_FLAGS -> deactivated to the same state as + TPM_PERMANENT_FLAGS -> deactivated + */ + tpm_state->tpm_stclear_flags.deactivated = tpm_state->tpm_permanent_flags.deactivated; + /* f. The TPM MUST set the TPM_STANY_DATA fields to: */ + /* i. TPM_STANY_DATA->contextNonceSession is set to all zeros */ + /* ii. TPM_STANY_DATA->contextCount is set to 0 */ + /* iii. TPM_STANY_DATA->contextList is set to 0 */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* g. The TPM MUST set TPM_STCLEAR_DATA fields to: */ + /* i. Invalidate contextNonceKey */ + /* ii. countID to zero */ + /* iii. OwnerReference to TPM_KH_OWNER */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearData_Init() */ + /* h. The TPM MUST set the following TPM_STCLEAR_FLAGS to */ + /* i. bGlobalLock to FALSE */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* i. Determine which keys should remain in the TPM */ + /* i. For each key that has a valid preserved value in the TPM */ + /* (1) if parentPCRStatus is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* (2) if isVolatile is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* NOTE Since TPM_Global_Init() calls TPM_KeyHandleEntries_Init(), there are no keys + remaining. Since this TPM implementation loads keys into volatile memory, not NVRAM, no + keys are preserved at ST_CLEAR. */ + /* ii. Keys under control of the OwnerEvict flag MUST stay resident in the TPM */ + /* NOTE Done by TPM_PermanentAll_NVLoad() */ + /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at + TPM_Startup(ST_Clear) */ + TPM_NVIndexEntries_StClear(&(tpm_state->tpm_nv_index_entries)); + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_STATE) rev 100 + */ + +TPM_RESULT TPM_Startup_State(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_State:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. If the TPM has no state to restore the TPM MUST set the internal state such that it + returns TPM_FAILEDSELFTEST to all subsequent commands */ + /* b. The TPM MAY determine for each session type (authorization, transport, DAA, ...) to + release or maintain the session information. The TPM reports how it manages sessions in + the TPM_GetCapability command. */ + /* c. The TPM SHALL take all necessary actions to ensure that all PCRs contain valid + preserved values. If the TPM is unable to successfully complete these actions, it SHALL + enter the TPM failure mode. */ + /* i. For resettable PCR the TPM MUST set the value of TPM_STCLEAR_DATA -> PCR[] to the + resettable PCR default value. The TPM MUST NOT restore a resettable PCR to a preserved + value */ + /* d. The TPM MAY initialize auditDigest to all zeros */ + /* i. Otherwise, the TPM SHALL take all actions necessary to ensure that auditDigest + contains a valid value. If the TPM is unable to successfully complete these actions, the + TPM SHALL initialize auditDigest to all zeros and SHALL set the internal state such that + the TPM returns TPM_FAILEDSELFTEST to all subsequent commands. */ + /* e. The TPM MUST restore the following flags to their preserved states: */ + /* i. All values in TPM_STCLEAR_FLAGS */ + /* ii. All values in TPM_STCLEAR_DATA */ + /* f. The TPM MUST restore all keys that have a valid preserved value */ + /* NOTE Owner evict keys are loaded at TPM_PermanentAll_NVLoad() */ + returnCode = TPM_SaveState_NVLoad(tpm_state); /* returns TPM_RETRY on non-existent file */ + } + /* g. The TPM resumes normal operation. If the TPM is unable to resume normal operation, it + SHALL enter the TPM failure mode. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Startup_State: Error restoring state\n"); + returnCode = TPM_FAILEDSELFTEST; + printf(" TPM_Startup_State: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_DEACTIVATED) rev 97 + */ + +TPM_RESULT TPM_Startup_Deactivated(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Deactivated:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Invalidate sessions */ + /* i. Ensure that all resources associated with saved and active sessions are invalidated */ + /* NOTE Done at TPM_MainInit() */ + /* b. The TPM MUST set TPM_STCLEAR_FLAGS -> deactivated to TRUE */ + tpm_state->tpm_stclear_flags.deactivated = TRUE; + } + return returnCode; +} + +#if 0 +/* TPM_Startup_Any() rev 96 + + Handles Actions common to all TPM_Startup options. +*/ + +TPM_RESULT TPM_Startup_Any(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Any:\n"); + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not exist. */ + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + return returnCode; +} +#endif + +/* 3.3 TPM_SaveState rev 111 + + This warns a TPM to save some state information. + + If the relevant shielded storage is non-volatile, this command need have no effect. + + If the relevant shielded storage is volatile and the TPM alone is unable to detect the loss of + external power in time to move data to non-volatile memory, this command should be presented + before the TPM enters a low or no power state. + + Resettable PCRs are tied to platform state that does not survive a sleep state. If the PCRs did + not reset, they would falsely indicate that the platform state was already present when it came + out of sleep. Since some setup is required first, there would be a gap where PCRs indicated the + wrong state. Therefore, the PCRs must be recreated. +*/ + +TPM_RESULT TPM_Process_SaveState(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveState: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveState: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Preserved values MUST be non-volatile. */ + /* 2. If data is never stored in a volatile medium, that data MAY be used as preserved data. In + such cases, no explicit action may be required to preserve that data. */ + /* 3. If an explicit action is required to preserve data, it MUST be possible for the TPM to + determine whether preserved data is valid. */ + /* 4. If the parameter mirrored by a preserved value is altered, all preserved values MUST be + declared invalid. */ + if (returnCode == TPM_SUCCESS) { + /* Determine if TPM_SaveState was called from within a transport session. The TPM MAY save + transport sessions as part of the saved state. Since this TPM implements that option, + there's no point in saving the state, because it would be immediately invalidated during + the transport response. Return an error to indicate that the state was not saved. */ + if (transportInternal != NULL) { + printf("TPM_Process_SaveState: Error, called from transport session\n"); + returnCode = TPM_NO_WRAP_TRANSPORT; + } + } + /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and + the audit occurs before the state is saved. If an error occurs while or after the state is + saved, the audit still occurs. + */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* 5. The TPM MAY declare all preserved value is invalid in response to any command other that + TPM_Init. */ + /* NOTE Done by TPM_GetInParamDigest(), which is called by all ordinals */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved */ + /* 8. The contents of sessions (authorization, transport, DAA etc.) MAY be preserved as reported + by TPM_GetCapability */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SaveState_NVStore(tpm_state); + } + /* store the state in NVRAM */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveState: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + 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 */ + } + /* Special case, no output parameter audit */ + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm12/tpm_startup.h b/src/tpm12/tpm_startup.h new file mode 100644 index 0000000..bc72328 --- /dev/null +++ b/src/tpm12/tpm_startup.h @@ -0,0 +1,136 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Startup and State */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_startup.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_STARTUP_H +#define TPM_STARTUP_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + Startup +*/ + +TPM_RESULT TPM_Startup_Clear(tpm_state_t *tpm_state); +TPM_RESULT TPM_Startup_State(tpm_state_t *tpm_state); +TPM_RESULT TPM_Startup_Deactivated(tpm_state_t *tpm_state); +#if 0 +TPM_RESULT TPM_Startup_Any(tpm_state_t *tpm_state); +#endif + +/* + Save State +*/ + +TPM_RESULT TPM_SaveState_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SaveState_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_SaveState_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_SaveState_NVStore(tpm_state_t *tpm_state); +TPM_RESULT TPM_SaveState_NVDelete(tpm_state_t *tpm_state, + TPM_BOOL mustExist); + +void TPM_SaveState_IsSaveKey(TPM_BOOL *save, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +/* + Volatile State +*/ + +TPM_RESULT TPM_VolatileAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_VolatileAll_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); +TPM_RESULT TPM_VolatileAll_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_VolatileAll_NVStore(tpm_state_t *tpm_state); + +/* + Compiled in TPM Parameters +*/ + +TPM_RESULT TPM_Parameters_Load(unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Store(TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_Parameters_Check8(uint8_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Check16(uint16_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Check32(uint32_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_Reset(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 TPM_Process_Startup(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 TPM_Process_SaveState(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); + +#endif diff --git a/src/tpm12/tpm_storage.c b/src/tpm12/tpm_storage.c new file mode 100644 index 0000000..c3cd1ac --- /dev/null +++ b/src/tpm12/tpm_storage.c @@ -0,0 +1,3593 @@ +/********************************************************************************/ +/* */ +/* Storage Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_storage.c 4442 2011-02-14 20:20:01Z 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 <stdlib.h> +#include <string.h> + +#include "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_structures.h" +#include "tpm_ver.h" + +#include "tpm_storage.h" + +/* local function prototypes */ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd); + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, + TPM_BOOL *key_added, + TPM_SECRET **hmacKey, + TPM_AUTH_SESSION_DATA **auth_session_data, + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth); + +/* + TPM_BOUND_DATA +*/ + +/* TPM_BoundData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_BoundData_Init(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Init:\n"); + TPM_StructVer_Init(&(tpm_bound_data->ver)); + tpm_bound_data->payload = TPM_PT_BIND; + tpm_bound_data->payloadDataSize = 0; + tpm_bound_data->payloadData = NULL; + return; +} + +/* TPM_BoundData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_BoundData_Init() + After use, call TPM_BoundData_Delete() to free memory +*/ + +TPM_RESULT TPM_BoundData_Load(TPM_BOUND_DATA *tpm_bound_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Load:\n"); + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_bound_data->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_bound_data->payload), stream, stream_size); + } + if ((rc == 0) && (*stream_size > 0)){ + /* There is no payloadData size in the serialized data. Assume it consumes the rest of the + stream */ + tpm_bound_data->payloadDataSize = *stream_size; + rc = TPM_Malloc(&(tpm_bound_data->payloadData), tpm_bound_data->payloadDataSize); + } + if ((rc == 0) && (*stream_size > 0)){ + memcpy(tpm_bound_data->payloadData, *stream, tpm_bound_data->payloadDataSize); + *stream += tpm_bound_data->payloadDataSize; + *stream_size -= tpm_bound_data->payloadDataSize; + } + return rc; +} + +#if 0 +/* TPM_BoundData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This structure serialization assumes that the payloadDataSize member indicates the size of + payloadData. +*/ + +TPM_RESULT TPM_BoundData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_BOUND_DATA *tpm_bound_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Store:\n"); + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_bound_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_bound_data->payloadData, + tpm_bound_data->payloadDataSize); + } + return rc; +} +#endif + +/* TPM_BoundData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the bound_data + sets pointers to NULL + calls TPM_BoundData_Init to set members back to default values + The bound_data itself is not freed +*/ + +void TPM_BoundData_Delete(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Delete:\n"); + if (tpm_bound_data != NULL) { + free(tpm_bound_data->payloadData); + TPM_BoundData_Init(tpm_bound_data); + } + return; +} + +/* + TPM_SEALED_DATA +*/ + +/* TPM_SealedData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SealedData_Init(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Init:\n"); + tpm_sealed_data->payload = TPM_PT_SEAL; + TPM_Secret_Init(tpm_sealed_data->authData); + TPM_Secret_Init(tpm_sealed_data->tpmProof); + TPM_Digest_Init(tpm_sealed_data->storedDigest); + TPM_SizedBuffer_Init(&(tpm_sealed_data->data)); + return; +} + +/* TPM_SealedData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SealedData_Init() + After use, call TPM_SealedData_Delete() to free memory +*/ + +TPM_RESULT TPM_SealedData_Load(TPM_SEALED_DATA *tpm_sealed_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SealedData_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_sealed_data->payload), stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->authData, stream, stream_size); + } + /* load tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->tpmProof, stream, stream_size); + } + /* load storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_sealed_data->storedDigest, stream, stream_size); + } + /* load dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_sealed_data->data), stream, stream_size); + } + return rc; +} + +/* TPM_SealedData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SealedData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SEALED_DATA *tpm_sealed_data) +{ + TPM_RESULT rc = 0; + printf(" TPM_SealedData_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_sealed_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->authData); + } + /* store tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->tpmProof); + } + /* store storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_sealed_data->storedDigest); + } + /* store dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sealed_data->data)); + } + return rc; +} + +/* TPM_SealedData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SealedData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SealedData_Delete(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Delete:\n"); + if (tpm_sealed_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sealed_data->data)); + TPM_SealedData_Init(tpm_sealed_data); + } + return; +} + +/* TPM_SealedData_GenerateEncData() generates an enc_data structure by serializing the + TPM_SEALED_DATA structure and encrypting the result using the public key. +*/ + +TPM_RESULT TPM_SealedData_GenerateEncData(TPM_SIZED_BUFFER *enc_data, + const TPM_SEALED_DATA *tpm_sealed_data, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_SEALED_DATA serialization */ + + printf(" TPM_SealedData_GenerateEncData\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_SEALED_DATA */ + if (rc == 0) { + rc = TPM_SealedData_Store(&sbuffer, tpm_sealed_data); + } + /* encrypt the TPM_SEALED_DATA serialization buffer with the public key, and place + the result in the encData members */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(enc_data, &sbuffer, tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SealedData_DecryptEncData() decrypts the enc_data using the private key. The + result is deserialized and stored in the TPM_SEALED_DATA structure. + +*/ + +TPM_RESULT TPM_SealedData_DecryptEncData(TPM_SEALED_DATA *tpm_sealed_data, /* result */ + TPM_SIZED_BUFFER *enc_data, /* encrypted input */ + TPM_KEY *tpm_key) /* key for decrypting */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_SealedData_DecryptEncData:\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted data */ + enc_data->buffer, /* encrypted data */ + enc_data->size, /* encrypted data size */ + tpm_key); + } + /* load the TPM_SEALED_DATA structure from the decrypted data stream */ + if (rc == 0) { + /* use temporary variables, because TPM_SealedData_Load() moves the stream */ + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_SealedData_Load(tpm_sealed_data, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + + +/* + TPM_STORED_DATA +*/ + +/* TPM_StoredData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StoredData_Init(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Init: v%u\n", version); + if (version == 1) { + TPM_StructVer_Init(&(tpm_stored_data->ver)); + } + else { + ((TPM_STORED_DATA12 *)tpm_stored_data)->tag = TPM_TAG_STORED_DATA12; + ((TPM_STORED_DATA12 *)tpm_stored_data)->et = 0x0000; + } + TPM_SizedBuffer_Init(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Init(&(tpm_stored_data->encData)); + tpm_stored_data->tpm_seal_info = NULL; + return; +} + +/* TPM_StoredData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StoredData_Init() + After use, call TPM_StoredData_Delete() to free memory + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12 and returns the 'version'. +*/ + +TPM_RESULT TPM_StoredData_Load(TPM_STORED_DATA *tpm_stored_data, + unsigned int *version, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* Peek at the first byte to guess the version number. The data is verified later. + TPM_STORED_DATA is 01,01,00,00 TPM_STORED_DATA12 is 00,16,00,00 */ + if ((rc == 0) && (*stream_size > 0)) { + if (**stream == 0x01) { + *version = 1; + } + else { + *version = 2; + } + printf(" TPM_StoredData_Load: v%u\n", *version); + } + /* 1.1 load ver */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_Load(&(tpm_stored_data->ver), stream, stream_size); + } + /* 1.2 load tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->tag), stream, stream_size); + } + /* 1.2 load et */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->et), stream, stream_size); + } + /* check the TPM_STORED_DATA structure version */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_CheckVer(&(tpm_stored_data->ver)); + } + /* check the TPM_STORED_DATA12 structure tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_StoredData_CheckTag((TPM_STORED_DATA12 *)tpm_stored_data); + } + /* load sealInfoSize and sealInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->sealInfo), stream, stream_size); + } + /* load the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + if (rc == 0) { + if (*version == 1) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_stored_data->tpm_seal_info), + &(tpm_stored_data->sealInfo)); + } + else { + rc = TPM_PCRInfoLong_CreateFromBuffer + (&(((TPM_STORED_DATA12 *)tpm_stored_data)->tpm_seal_info_long), + &(tpm_stored_data->sealInfo)); + } + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->encData), stream, stream_size); + } + return rc; +} + +/* TPM_StoredData_StoreClearData() serializes a TPM_STORED_DATA structure, excluding encData, + appending results to 'sbuffer'. + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_StoreClearData(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_StoreClearData: v%u\n", version); + /* 1.1 store ver */ + if ((rc == 0) && (version == 1)) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_stored_data->ver)); + } + /* 1.2 store tag */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->tag); + } + /* 1.2 store et */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->et); + } + /* store sealInfoSize and sealInfo */ + if (rc == 0) { + /* copy cache to sealInfoSize and sealInfo */ + if (version == 1) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy sealInfoSize and sealInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->sealInfo)); + } + return rc; +} + +/* TPM_StoredData_Store() + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_Store: v%u\n", version); + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(sbuffer, tpm_stored_data, version); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->encData)); + } + return rc; +} + +/* TPM_StoredData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_StoredData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_StoredData_Delete(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Delete: v%u\n", version); + if (tpm_stored_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Delete(&(tpm_stored_data->encData)); + if (version == 1) { + TPM_PCRInfo_Delete(tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + else { + TPM_PCRInfoLong_Delete((TPM_PCR_INFO_LONG *)tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + TPM_StoredData_Init(tpm_stored_data, version); + } + return; +} + +/* TPM_StoredData_CheckTag() verifies the tag and et members of a TPM_STORED_DATA12 structure + + */ + +TPM_RESULT TPM_StoredData_CheckTag(TPM_STORED_DATA12 *tpm_stored_data12) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_CheckTag:\n"); + if (rc == 0) { + if (tpm_stored_data12->tag != TPM_TAG_STORED_DATA12) { + printf("TPM_StoredData_CheckTag: Error, tag expected %04x found %04hx\n", + TPM_TAG_STORED_DATA12, tpm_stored_data12->tag); + rc = TPM_BAD_VERSION; + } + } + return rc; +} + +/* TPM_StoredData_GenerateDigest() generates a TPM_DIGEST over the TPM_STORED_DATA structure + excluding the encDataSize and encData members. +*/ + +TPM_RESULT TPM_StoredData_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORED_DATA serialization */ + + printf(" TPM_StoredData_GenerateDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORED_DATA excluding the encData fields */ + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(&sbuffer, tpm_stored_data, version); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Processing Functions +*/ + +/* TPM_SealCryptCommon() rev 98 + + Handles the encrypt/decrypt actions common to TPM_Sealx and TPM_Unseal + + 'encrypt TRUE for encryption, FALSE for decryption + + The output o1 must be freed by the caller. +*/ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, /* freed by caller */ + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd) +{ + TPM_RESULT rc = 0; + BYTE *x1; /* XOR string, MGF1 output */ + TPM_DIGEST ctr; /* symmetric key algorithm CTR */ + + printf(" TPM_SealCryptCommon:\n"); + x1 = NULL; /* freed @1 */ + + /* allocate for the output o1 */ + if (rc == TPM_SUCCESS) { + rc = TPM_Malloc(o1, inData->size); /* freed by caller */ + } + if (rc == TPM_SUCCESS) { + TPM_PrintFourLimit(" TPM_SealCryptCommon: input data", inData->buffer, inData->size); + } + switch (adipEncScheme) { + case TPM_ET_XOR: + printf(" TPM_SealCryptCommon: TPM_ET_XOR\n"); + if (rc == TPM_SUCCESS) { + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + rc = TPM_MGF1_GenerateArray(&x1, /* MGF1 array */ + inData->size, /* MGF1 array length */ + + TPM_NONCE_SIZE + + TPM_NONCE_SIZE + + sizeof("XOR") -1 + + TPM_DIGEST_SIZE, /* seed length */ + + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + sizeof("XOR") -1, "XOR", + TPM_DIGEST_SIZE, auth_session_data->sharedSecret, + 0, NULL); + } + /* ii. Create o1 by XOR of d1 -> data and X1 */ + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: XOR key", x1); + TPM_XOR(*o1, inData->buffer, x1, inData->size); + } + break; + case TPM_ET_AES128_CTR: + printf(" TPM_SealCryptCommon: TPM_ET_AES128_CTR\n"); + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (rc == TPM_SUCCESS) { + rc = TPM_SHA1(ctr, + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + 0, NULL); + } + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: AES key", auth_session_data->sharedSecret); + TPM_PrintFour(" TPM_SealCryptCommon: CTR", ctr); + rc = TPM_SymmetricKeyData_CtrCrypt(*o1, /* output data */ + inData->buffer, /* input data */ + inData->size, /* data size */ + auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, /* key size */ + ctr, /* CTR */ + TPM_DIGEST_SIZE); /* CTR size */ + } + break; + default: + printf("TPM_SealCryptCommon: Error, unsupported adipEncScheme %02x\n", adipEncScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + if (rc == 0) { + TPM_PrintFour(" TPM_SealCryptCommon: output data", *o1); + + } + free(x1); /* @1 */ + return rc; +} + +/* 10.1 TPM_Seal rev 110 + + The SEAL operation allows software to explicitly state the future "trusted" configuration that + the platform must be in for the secret to be revealed. The SEAL operation also implicitly + includes the relevant platform configuration (PCR-values) when the SEAL operation was + performed. The SEAL operation uses the tpmProof value to BIND the blob to an individual TPM. + + TPM_Seal is used to encrypt private objects that can only be decrypted using TPM_Unseal. +*/ + +TPM_RESULT TPM_Process_Seal(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data. */ + TPM_SIZED_BUFFER pcrInfo; /* The PCR selection information. The caller MAY use + TPM_PCR_INFO_LONG. */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. Must be an OS_AP session for this + command. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + unsigned int v1PcrVersion = 1; /* pcrInfo version */ + TPM_STORED_DATA12 *s1_12; + TPM_PCR_INFO tpm_pcr_info; /* deserialized pcrInfo v1 */ + TPM_PCR_INFO_LONG tpm_pcr_info_long; /* deserialized pcrInfo v2 */ + unsigned char *stream; + uint32_t stream_size; + TPM_DIGEST a1Auth; + TPM_SEALED_DATA s2SealedData; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA s1StoredData; /* Encrypted, integrity-protected data object that is the + result of the TPM_Seal operation. Returned as + SealedData */ + + printf("TPM_Process_Seal: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); /* freed @3, default is v1 */ + TPM_PCRInfo_Init(&tpm_pcr_info); /* freed @4 */ + TPM_PCRInfoLong_Init(&tpm_pcr_info_long); /* freed @5 */ + TPM_SealedData_Init(&s2SealedData); /* freed @6 */ + s1_12 = (TPM_STORED_DATA12 *)&s1StoredData; /* to avoid casts */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: keyHandle %08x\n", keyHandle); + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: Sealing %u bytes\n", inData.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_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Seal: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Seal: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Seal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Seal: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Determine the version of pcrInfo */ + if (returnCode == TPM_SUCCESS) { + /* a. If pcrInfoSize is 0 */ + if (pcrInfo.size == 0) { + v1PcrVersion = 1; /* i. set V1 to 1 */ + } + else { /* b. Else */ + /* i. Point X1 as TPM_PCR_INFO_LONG structure to pcrInfo */ + /* ii. If X1 -> tag is TPM_TAG_PCR_INFO_LONG */ + if (htons(*(uint16_t *)(pcrInfo.buffer)) == TPM_TAG_PCR_INFO_LONG) { + v1PcrVersion = 2; /* (1) Set V1 to 2 */ + } + else { /* iii. Else */ + v1PcrVersion = 1; /* (1) Set V1 to 1 */ + } + } + /* 6. If V1 is 1 then */ + /* a. Create S1 a TPM_STORED_DATA structure */ + /* 7. else */ + /* a. Create S1 a TPM_STORED_DATA12 structure */ + /* b. Set S1 -> et to 0 */ + /* 8. Set S1 -> encDataSize to 0 */ + /* 9. Set S1 -> encData to all zeros */ + printf("TPM_Process_Seal: V%u\n", v1PcrVersion); + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); + /* 10. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is either a TPM_PCR_INFO or a TPM_PCR_INFO_LONG */ + } + /* 11. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Seal: Creating PCR digest\n"); + /* assign the stream, so pcrInfo is not altered */ + stream = pcrInfo.buffer; + stream_size = pcrInfo.size; + /* a. if V1 is 1 then */ + if (v1PcrVersion == 1) { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_Load(&tpm_pcr_info, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> pcrSelection to pcrInfo -> pcrSelection */ + returnCode = TPM_PCRInfo_CreateFromBuffer(&(s1StoredData.tpm_seal_info), &pcrInfo); + } + /* iii. Create h1 the composite hash of the PCR selected by pcrInfo -> pcrSelection */ + /* iv. Set S1 -> sealInfo -> digestAtCreation to h1 */ + /* NOTE hash directly to destination. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_PCRSelection_GenerateDigest(s1StoredData.tpm_seal_info->digestAtCreation, + &(tpm_pcr_info.pcrSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* v. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* NOTE digestAtRelease copied during TPM_PCRInfo_CreateFromBuffer() */ + } + /* b. else (v1 is 2) */ + else { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX + on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_Load(&tpm_pcr_info_long, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection + */ + /* iii. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection + */ + /* iv. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* v. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1_12->tpm_seal_info_long), + &pcrInfo); + } + if (returnCode == TPM_SUCCESS) { + /* vi. Create h2 the composite hash of the PCR selected by pcrInfo -> + creationPCRSelection */ + /* vii. Set S1 -> sealInfo -> digestAtCreation to h2 */ + /* NOTE hash directly to destination. */ + returnCode = + TPM_PCRSelection_GenerateDigest(s1_12->tpm_seal_info_long->digestAtCreation, + &(tpm_pcr_info_long.creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* viii. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_FLAGS -> + localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1_12->tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + } + /* 12. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 13. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 14. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, + &s1StoredData, v1PcrVersion); + } + if (returnCode == TPM_SUCCESS) { + /* e. Set S2 -> authData to a1 */ + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to inData */ + returnCode = TPM_SizedBuffer_Copy(&(s2SealedData.data), &inData); + } + /* 15. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + TPM_BAD_DATASIZE on error */ + /* 16. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 17. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 18. Set S1 -> encDataSize to the size of s3 */ + /* 19. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Seal: 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; + /* 20. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, &s1StoredData, v1PcrVersion); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(&s1StoredData, v1PcrVersion); /* @3 */ + TPM_PCRInfo_Delete(&tpm_pcr_info); /* @4 */ + TPM_PCRInfoLong_Delete(&tpm_pcr_info_long); /* @5 */ + TPM_SealedData_Delete(&s2SealedData); /* @6 */ + return rcf; +} + +/* 10.7 TPM_Sealx rev 110 + + The TPM_Sealx command works exactly like the TPM_Seal command with the additional requirement of + encryption for the inData parameter. This command also places in the sealed blob the information + that the TPM_Unseal also requires encryption. + + TPM_Sealx requires the use of 1.2 data structures. The actions are the same as TPM_Seal without + the checks for 1.1 data structure usage. +*/ + +TPM_RESULT TPM_Process_Sealx(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data */ + TPM_SIZED_BUFFER pcrInfo; /* If 0 there are no PCR registers in use. pcrInfo MUST use + TPM_PCR_INFO_LONG */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization. Must be an OSAP session for this command. + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA12 s1StoredData; /* Encrypted, integrity-protected data object that + is the result of the TPM_Seal operation. Returned + as SealedData */ + TPM_STORED_DATA *s1_11; /* 1.1 version to avoid casts */ + TPM_SEALED_DATA s2SealedData; + TPM_DIGEST a1Auth; + BYTE *o1DecryptedData; + + printf("TPM_Process_Sealx: Ordinal Entry\n"); + s1_11 = (TPM_STORED_DATA *)&s1StoredData; /* 1.1 version to avoid casts */ + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(s1_11, 2); /* freed @3 */ + TPM_SealedData_Init(&s2SealedData); /* freed @4 */ + o1DecryptedData = NULL; /* freed @5 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Sealing %u bytes\n", inData.size); + TPM_PrintFourLimit("TPM_Process_Sealx: Sealing data", inData.buffer, inData.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_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Sealx: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Sealx: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Sealx: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Sealx: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Create S1 a TPM_STORED_DATA12 structure */ + /* 6. Set S1 -> encDataSize to 0 */ + /* 7. Set S1 -> encData to all zeros */ + /* NOTE: Done by TPM_StoredData_Init() */ + /* 8. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is a TPM_PCR_INFO_LONG */ + /* 9. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Sealx: Setting sealInfo to pcrInfo\n"); + /* initializing the s -> TPM_PCR_INFO_LONG cache to the contents of pcrInfo */ + /* a. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1StoredData.tpm_seal_info_long), + &pcrInfo); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_BADINDEX; + } + } + /* b. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection */ + /* c. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection */ + /* d. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* e. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + /* f. Create h2 the composite hash of the PCR selected by pcrInfo -> creationPCRSelection */ + /* g. Set S1 -> sealInfo -> digestAtCreation to h2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest + (s1StoredData.tpm_seal_info_long->digestAtCreation, + &(s1StoredData.tpm_seal_info_long->creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* h. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_DATA -> localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1StoredData.tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 10. Create S2 a TPM_SEALED_DATA structure */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* 11.Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Decrypting encAuth\n"); + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, /* a1 even */ + NULL, /* a1 odd (2nd encAuth) */ + encAuth, /* encAuthEven */ + auth_session_data, + NULL, /* nonceOdd */ + NULL, /* encAuthOdd */ + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_Sealx: Decrypted Auth", a1Auth); + /* a. If authHandle indicates XOR encryption for the AuthData secrets */ + if (auth_session_data->adipEncScheme == TPM_ET_XOR) { + /* i. Set S1 -> et to TPM_ET_XOR || TPM_ET_KEY */ + /* (1) TPM_ET_KEY is added because TPM_Unseal uses zero as a special value indicating no + encryption. */ + s1StoredData.et = TPM_ET_XOR | TPM_ET_KEY; + } + /* b. Else */ + else { + /* i. Set S1 -> et to algorithm indicated by authHandle */ + s1StoredData.et = auth_session_data->adipEncScheme << 8; + } + } + /* 12. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 13. If authHandle indicates XOR encryption */ + /* a. Use MGF1 to create string X2 of length inDataSize. The inputs to MGF1 are; + authLastNonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four concatenated + values form the Z value that is the seed for MFG1. */ + /* b. Create o1 by XOR of inData and x2 */ + /* 14. Else */ + /* a. Create o1 by decrypting inData using the algorithm indicated by authHandle */ + /* b. Key is from authHandle -> sharedSecret */ + /* c. CTR is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: decrypting inData\n"); + returnCode = TPM_SealCryptCommon(&o1DecryptedData, /* freed by caller */ + auth_session_data->adipEncScheme, + &inData, + auth_session_data, + nonceOdd); + + } + /* 15. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, s1_11, 2); + } + /* e. Set S2 -> authData to a1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to o1 */ + returnCode = TPM_SizedBuffer_Set(&(s2SealedData.data), inData.size, o1DecryptedData); + } + /* 16. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + */ + /* TPM_BAD_DATASIZE on error */ + /* 17. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 18. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 19. Set S1 -> encDataSize to the size of s3 */ + /* 20. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Encrypting sealed data\n"); + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sealx: 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; + /* 21. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, s1_11, 2); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(s1_11, 2); /* @3 */ + TPM_SealedData_Delete(&s2SealedData); /* @4 */ + free(o1DecryptedData); /* @5 */ + return rcf; +} + +/* 10.2 TPM_Unseal rev 110 + + The TPM_Unseal operation will reveal TPM_Sealed data only if it was encrypted on this platform + and the current configuration (as defined by the named PCR contents) is the one named as + qualified to decrypt it. Internally, TPM_Unseal accepts a data blob generated by a TPM_Seal + operation. TPM_Unseal decrypts the structure internally, checks the integrity of the resulting + data, and checks that the PCR named has the value named during TPM_Seal. Additionally, the + caller must supply appropriate authorization data for blob and for the key that was used to seal + that data. + + If the integrity, platform configuration and authorization checks succeed, the sealed data is + returned to the caller; otherwise, an error is generated. +*/ + +TPM_RESULT TPM_Process_Unseal(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 a loaded key that can unseal the data. */ + TPM_STORED_DATA inData; /* The encrypted data generated by TPM_Seal. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + TPM_AUTHHANDLE dataAuthHandle; /* The authorization handle used to authorize inData. */ + TPM_NONCE datanonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueDataSession = TRUE; /* Continue usage flag for dataAuthHandle. */ + TPM_AUTHDATA dataAuth; /* The authorization digest for the encrypted entity. HMAC + key: entity.usageAuth. */ + + /* processing */ + 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_BOOL dataAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *data_auth_session_data = NULL; /* session data for dataAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_SECRET *dataHmacKey; + unsigned int v1StoredDataVersion = 1; /* version of TPM_STORED_DATA + inData */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + TPM_SEALED_DATA d1SealedData; + TPM_DIGEST h1StoredDataDigest; + TPM_STORED_DATA12 *s2StoredData; + BYTE *o1Encrypted; /* For ADIP encryption */ + TPM_ADIP_ENC_SCHEME adipEncScheme; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t secretSize = 0; /* Decrypted data that had been sealed */ + BYTE *secret = NULL; + + printf("TPM_Process_Unseal: Ordinal Entry\n"); + TPM_StoredData_Init(&inData, v1StoredDataVersion); /* freed @1, default is v1 */ + TPM_SealedData_Init(&d1SealedData); /* freed @2 */ + o1Encrypted = NULL; /* freed @3 */ + s2StoredData = (TPM_STORED_DATA12 *)&inData; /* inData when it's a TPM_STORED_DATA12 + structure */ + /* + 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 inData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: parentHandle %08x\n", parentHandle); + returnCode = TPM_StoredData_Load(&inData, &v1StoredDataVersion, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: inData is v%u\n", v1StoredDataVersion); + } + /* 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_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_Unseal: authHandle %08x\n", authHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&dataAuthHandle, + &dataAuthHandleValid, + datanonceOdd, + &continueDataSession, + dataAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: dataAuthHandle %08x\n", dataAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Unseal: 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; + dataAuthHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. The TPM MUST validate that parentAuth authorizes the use of the key in parentHandle, on + error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_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, + parentAuth); /* Authorization digest for input */ + } + /* if there are no parent auth parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Unseal: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. If the keyUsage field of the key indicated by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM MUST return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Unseal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM MUST check that the TPM_KEY_FLAGS -> Migratable flag has the value FALSE in the + key indicated by parentKeyHandle. If not, the TPM MUST return the error code + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Unseal: Error, key keyFlags %08x indicates migratable\n", + parentKey->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Determine the version of inData */ + /* a. If inData -> tag = TPM_TAG_STORED_DATA12 */ + /* i. Set V1 to 2 */ + /* ii. Map S2 a TPM_STORED_DATA12 structure to inData */ + /* b. Else If inData -> ver = 1.1 */ + /* i. Set V1 to 1 */ + /* ii. Map S2 a TPM_STORED_DATA structure to inData */ + /* c. Else */ + /* i. Return TPM_BAD_VERSION */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* The extra indent of error checking is required because the next steps all return + TPM_NOTSEALED_BLOB on error */ + if (returnCode == TPM_SUCCESS) { + /* 5. Create d1 by decrypting S2 -> encData using the key pointed to by parentHandle */ + printf("TPM_Process_Unseal: Decrypting encData\n"); + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_DecryptEncData(&d1SealedData, /* TPM_SEALED_DATA */ + &(inData.encData), + parentKey); + } + /* 6. Validate d1 */ + /* a. d1 MUST be a TPM_SEALED_DATA structure */ + /* NOTE Done during TPM_SealedData_DecryptEncData() */ + /* b. d1 -> tpmProof MUST match TPM_PERMANENT_DATA -> tpmProof */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Sealed data size %u\n", d1SealedData.data.size); + TPM_PrintFour("TPM_Process_Unseal: Sealed data", d1SealedData.data.buffer); + printf("TPM_Process_Unseal: Checking tpmProof\n"); + returnCode = TPM_Secret_Compare(d1SealedData.tpmProof, + tpm_state->tpm_permanent_data.tpmProof); + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> encDataSize to 0 */ + /* d. Set S2 -> encData to all zeros */ + /* NOTE: This would be done at cleanup */ + TPM_SizedBuffer_Delete(&(inData.encData)); + /* e. Create h1 the SHA-1 of S2 */ + returnCode = TPM_StoredData_GenerateDigest(h1StoredDataDigest, + &inData, v1StoredDataVersion); + } + /* f. d1 -> storedDigest MUST match h1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking storedDigest\n"); + returnCode = TPM_Digest_Compare(d1SealedData.storedDigest, h1StoredDataDigest); + } + /* g. d1 -> payload MUST be TPM_PT_SEAL */ + if (returnCode == TPM_SUCCESS) { + if (d1SealedData.payload != TPM_PT_SEAL) { + printf("TPM_Process_Unseal: Error, payload %02x not TPM_PT_SEAL\n", + d1SealedData.payload); + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* h. Any failure MUST return TPM_NOTSEALED_BLOB */ + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* 7. If S2 -> sealInfo is not 0 then */ + /* NOTE: Done by _CheckDigest() */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking PCR digest\n"); + /* a. If V1 is 1 then */ + if (v1StoredDataVersion == 1) { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> pcrSelection + */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = TPM_PCRInfo_CheckDigest(inData.tpm_seal_info, + tpm_state->tpm_stclear_data.PCRS); /* PCR array */ + } + /* b. If V1 is 2 then */ + else { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO_LONG structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> + releasePCRSelection */ + /* iii. Check that S2 -> pcrInfo -> localityAtRelease for TPM_STANY_DATA -> + localityModifier is TRUE */ + /* (1) For example if TPM_STANY_DATA -> localityModifier was 2 then S2 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = + TPM_PCRInfoLong_CheckDigest(s2StoredData->tpm_seal_info_long, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 8. The TPM MUST validate authorization to use d1 by checking that the HMAC calculation + using d1 -> authData as the shared secret matches the dataAuth. Return TPM_AUTHFAIL on + mismatch. */ + /* get the second session data */ + /* NOTE: While OSAP isn't specifically excluded, there is currently no way to set up an OSAP + session using TPM_SEALED_DATA as the entity */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&data_auth_session_data, + &dataHmacKey, + tpm_state, + dataAuthHandle, + TPM_PID_OIAP, /* currently require OIAP */ + 0, /* OSAP entity type */ + ordinal, + NULL, + &(d1SealedData.authData), /* OIAP */ + NULL); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *dataHmacKey, /* HMAC key */ + inParamDigest, + data_auth_session_data, /* authorization session */ + datanonceOdd, /* Nonce generated by system + associated with authHandle */ + continueDataSession, + dataAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 9. If V1 is 2 and S2 -> et specifies encryption (i.e. is not all zeros) then */ + if ((v1StoredDataVersion == 2) && (s2StoredData->et != 0x0000)) { + /* a. If tag is not TPM_TAG_RQU_AUTH2_COMMAND, return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_AUTH2_COMMAND) { + printf("TPM_Process_Unseal: Error, sealed with encryption but auth-1\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* b. Verify that the authHandle session type is TPM_PID_OSAP or TPM_PID_DSAP, return + TPM_BAD_MODE on error. */ + if (returnCode == TPM_SUCCESS) { + if ((auth_session_data->protocolID != TPM_PID_OSAP) && + (auth_session_data->protocolID != TPM_PID_DSAP)) { + printf("TPM_Process_Unseal: Error, sealed with encryption but OIAP\n"); + returnCode = TPM_BAD_MODE; + } + } + /* c. If MSB of S2 -> et is TPM_ET_XOR */ + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + /* d. Else */ + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + /* entity type MSB is ADIP encScheme */ + adipEncScheme = (s2StoredData->et >> 8) & 0x00ff; + printf("TPM_Process_Unseal: Encrypting the output, encScheme %02x\n", + adipEncScheme); + returnCode = TPM_SealCryptCommon(&o1Encrypted, + adipEncScheme, + &(d1SealedData.data), + auth_session_data, + nonceOdd); + secretSize = d1SealedData.data.size; + secret = o1Encrypted; + } + /* e. Set continueAuthSession to FALSE */ + continueAuthSession = FALSE; + } + /* 10. else */ + else { + printf("TPM_Process_Unseal: No output encryption\n"); + /* a. Set o1 to d1 -> data */ + secretSize = d1SealedData.data.size; + secret = d1SealedData.data.buffer; + } + } + /* 11. Set the return secret as o1 */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Unseal: 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 secretSize */ + returnCode = TPM_Sbuffer_Append32(response, secretSize); + } + if (returnCode == TPM_SUCCESS) { + /* return secret */ + returnCode = TPM_Sbuffer_Append(response, secret, secretSize); + /* 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_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *dataHmacKey, /* HMAC key */ + data_auth_session_data, + outParamDigest, + datanonceOdd, + continueDataSession); + } + /* 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); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueDataSession) && + dataAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, dataAuthHandle); + } + /* + cleanup + */ + TPM_StoredData_Delete(&inData, v1StoredDataVersion); /* @1 */ + TPM_SealedData_Delete(&d1SealedData); /* @2 */ + free(o1Encrypted); /* @3 */ + return rcf; +} + +/* 10.3 TPM_UnBind rev 87 + + TPM_UnBind takes the data blob that is the result of a Tspi_Data_Bind command and decrypts it + for export to the User. The caller must authorize the use of the key that will decrypt the + incoming blob. + + UnBind operates on a block-by-block basis, and has no notion of any relation between one block + and another. + + UnBind SHALL operate on a single block only. +*/ + +TPM_RESULT TPM_Process_UnBind(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + UnBind operations. */ + TPM_SIZED_BUFFER inData; /* Encrypted blob to be decrypted */ + TPM_AUTHHANDLE authHandle; /* The handle used for keyHandle authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the inputs and + use of keyHandle. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + uint32_t decrypt_data_size; /* resulting decrypted data size */ + BYTE *decrypt_data = NULL; /* The resulting decrypted data. */ + unsigned char *stream; + uint32_t stream_size; + TPM_BOUND_DATA tpm_bound_data; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + size_t outDataSize = 0; /* The length of the returned decrypted data */ + BYTE *outData = NULL; /* The resulting decrypted data. */ + + printf("TPM_Process_UnBind: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_BoundData_Init(&tpm_bound_data); /* freed @3 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get areaToSignSize and areaToSign parameters */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: keyHandle %08x\n", keyHandle); + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: UnBinding %u bytes\n", inData.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_UnBind: 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. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_UnBind: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_UnBind: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* 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, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 2. Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 3. If the keyUsage field of the key referenced by keyHandle does not have the value + TPM_KEY_BIND or TPM_KEY_LEGACY, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_BIND) && (key->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Error, invalid keyUsage %04hx\n", (key->keyUsage)); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* Get the TPM_RSA_KEY_PARMS associated with key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, &(key->algorithmParms)); + } + /* 4. Decrypt the inData using the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_RSAPrivateDecryptMalloc(&decrypt_data, /* decrypted data, freed @2 */ + &decrypt_data_size, /* actual size of decrypted data + data */ + inData.buffer, + inData.size, + key); + } + if (returnCode == TPM_SUCCESS) { + /* 5. if (keyHandle -> encScheme does not equal TPM_ES_RSAESOAEP_SHA1_MGF1) and (keyHandle + -> keyUsage equals TPM_KEY_LEGACY), */ + if ((key->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (key->keyUsage == TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Legacy key\n"); + /* a. The payload does not have TPM specific markers to validate, so no consistency + check can be performed. */ + /* b. Set the output parameter outData to the value of the decrypted value of + inData. (Padding associated with the encryption wrapping of inData SHALL NOT be + returned.) */ + outData = decrypt_data; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from the + decryption process. */ + outDataSize = decrypt_data_size; + } + /* 6. else */ + else { + printf("TPM_Process_UnBind: Payload is TPM_BOUND_DATA structure\n"); + /* a. Interpret the decrypted data under the assumption that it is a TPM_BOUND_DATA + structure, and validate that the payload type is TPM_PT_BIND */ + if (returnCode == TPM_SUCCESS) { + stream = decrypt_data; + stream_size = decrypt_data_size; + returnCode = TPM_BoundData_Load(&tpm_bound_data, + &stream, + &stream_size); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_bound_data.payload != TPM_PT_BIND) { + printf("TPM_Process_UnBind: Error, " + "TPM_BOUND_DATA->payload %02x not TPM_PT_BIND\n", + tpm_bound_data.payload); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* b. Set the output parameter outData to the value of TPM_BOUND_DATA -> + payloadData. (Other parameters of TPM_BOUND_DATA SHALL NOT be returned. Padding + associated with the encryption wrapping of inData SHALL NOT be returned.) */ + if (returnCode == TPM_SUCCESS) { + outData = tpm_bound_data.payloadData; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from + the decryption process and the interpretation of TPM_BOUND_DATA. */ + outDataSize = tpm_bound_data.payloadDataSize; + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_UnBind: 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; + /* 10. Return the computed outData */ + /* append outDataSize */ + returnCode = TPM_Sbuffer_Append32(response, outDataSize); + } + if (returnCode == TPM_SUCCESS) { + /* append outData */ + returnCode = TPM_Sbuffer_Append(response, outData, outDataSize); + /* 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, /* 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(&inData); /* @1 */ + free(decrypt_data); /* @2 */ + TPM_BoundData_Delete(&tpm_bound_data); /* @3 */ + return rcf; +} + +/* 10.4 TPM_CreateWrapKey rev 114 + + The TPM_CreateWrapKey command both generates and creates a secure storage bundle for asymmetric + keys. + + The newly created key can be locked to a specific PCR value by specifying a set of PCR registers. +*/ + +TPM_RESULT TPM_Process_CreateWrapKey(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 a loaded key that can perform key wrapping. */ + TPM_ENCAUTH dataUsageAuth; /* Encrypted usage authorization data for the key. */ + TPM_ENCAUTH dataMigrationAuth; /* Encrypted migration authorization data for the + key.*/ + TPM_KEY keyInfo; /* Information about key to be created, pubkey.keyLength and + keyInfo.encData elements are 0. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parent key + authorization. Must be an OSAP session. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest that authorizes the use of the + public key in 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; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_RSA_KEY_PARMS *keyInfoRSAParms = NULL; /* substructure of keyInfo */ + TPM_SECRET du1UsageAuth; + TPM_SECRET dm1MigrationAuth; + TPM_STORE_ASYMKEY *wrappedStoreAsymkey; /* substructure of wrappedKey */ + TPM_PCR_INFO wrappedPCRInfo; + int ver; /* TPM_KEY or TPM_KEY12 */ + + /* output parameters */ + TPM_KEY wrappedKey; /* The TPM_KEY structure which includes the public and + encrypted private key. MAY be TPM_KEY12 */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_CreateWrapKey: Ordinal Entry\n"); + TPM_Key_Init(&keyInfo); + TPM_Key_Init(&wrappedKey); + TPM_PCRInfo_Init(&wrappedPCRInfo); + /* + 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 dataUsageAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Authdata_Load(dataUsageAuth, &command, ¶mSize); + } + /* get dataMigrationAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(dataMigrationAuth, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateWrapKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, tpm_state, + parentHandle, + FALSE, /* not r/o, using to encrypt w/public key */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key pointed to by parentHandle. Return TPM_AUTHFAIL + on any error. */ + /* 2. Validate the session type for parentHandle is OSAP. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateWrapKey: sharedSecret", auth_session_data->sharedSecret); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle + */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 3. If the TPM is not designed to create a key of the type requested in keyInfo, return the + error code TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Checking key properties\n"); + returnCode = TPM_Key_CheckProperties(&ver, &keyInfo, 0, + tpm_state->tpm_permanent_flags.FIPS); + } + /* Get the TPM_RSA_KEY_PARMS associated with keyInfo */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: key parameters v = %d\n", ver); + returnCode = TPM_KeyParms_GetRSAKeyParms(&keyInfoRSAParms, &(keyInfo.algorithmParms)); + } + /* 4. Verify that parentHandle->keyUsage equals TPM_KEY_STORAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CreateWrapKey: Error, parent keyUsage not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. If parentHandle -> keyFlags -> migratable is TRUE and keyInfo -> keyFlags -> migratable is + FALSE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((parentKey->keyFlags & TPM_MIGRATABLE) && !(keyInfo.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CreateWrapKey: Error, parent not migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate key parameters */ + /* a. keyInfo -> keyUsage MUST NOT be TPM_KEY_IDENTITY or TPM_KEY_AUTHCHANGE. If it is, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((keyInfo.keyUsage == TPM_KEY_IDENTITY) || + (keyInfo.keyUsage == TPM_KEY_AUTHCHANGE)) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key usage %04x\n", + keyInfo.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If keyInfo -> keyFlags -> migrateAuthority is TRUE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (keyInfo.keyFlags & TPM_MIGRATEAUTHORITY) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key flags %08x\n", + keyInfo.keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS + c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 8. If keyInfo -> keyUsage equals TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. encScheme MUST be TPM_ES_RSAESOAEP_SHA1_MGF1 + iii. sigScheme MUST be TPM_SS_NONE + iv. key size MUST be 2048 + v. exponentSize MUST be 0 + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 9. Determine the version of key + a.If keyInfo -> ver is 1.1 + i. Set V1 to 1 + ii. Map wrappedKey to a TPM_KEY structure + iii. Validate all remaining TPM_KEY structures + b. Else if keyInfo -> tag is TPM_TAG_KEY12 + i. Set V1 to 2 + ii. Map wrappedKey to a TPM_KEY12 structure + iii. Validate all remaining TPM_KEY12 structures + NOTE Check done by TPM_Key_CheckProperties() + NOTE Map done by TPM_Key_GenerateRSA() + */ + /* 10..Create DU1 by decrypting dataUsageAuth according to the ADIP indicated by authHandle */ + /* 11. Create DM1 by decrypting dataMigrationAuth according to the ADIP indicated by + authHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessionData_Decrypt(du1UsageAuth, + dm1MigrationAuth, + dataUsageAuth, /* even encAuth */ + auth_session_data, + nonceOdd, + dataMigrationAuth, /* odd encAuth */ + TRUE); + } + /* 12. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 13. Generate asymmetric key according to algorithm information in keyInfo */ + /* 14. Fill in the wrappedKey structure with information from the newly generated key. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&wrappedKey, + tpm_state, + parentKey, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + keyInfo.keyUsage, + keyInfo.keyFlags, + keyInfo.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(keyInfo.algorithmParms), /* TPM_KEY_PARMS */ + keyInfo.tpm_pcr_info, /* TPM_PCR_INFO */ + keyInfo.tpm_pcr_info_long); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&wrappedStoreAsymkey, + &wrappedKey); + } + if (returnCode == TPM_SUCCESS) { + /* a. Set wrappedKey -> encData -> usageAuth to DU1 */ + TPM_Secret_Copy(wrappedStoreAsymkey->usageAuth, du1UsageAuth); + /* b. If the KeyFlags -> migratable bit is set to 1, the wrappedKey -> encData -> + migrationAuth SHALL contain the decrypted value from dataMigrationAuth. */ + if (wrappedKey.keyFlags & TPM_MIGRATABLE) { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, dm1MigrationAuth); + } + /* c. If the KeyFlags -> migratable bit is set to 0, the wrappedKey -> encData -> + migrationAuth SHALL be set to the value tpmProof */ + else { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, + tpm_state->tpm_permanent_data.tpmProof); + } + printf("TPM_Process_CreateWrapKey: wrappedKey.PCRInfoSize %d\n", wrappedKey.pcrInfo.size); + } + /* 15. If keyInfo->PCRInfoSize is non-zero. */ + /* a. If V1 is 1 */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO structure using the pcrSelection to + indicate the PCR's in use */ + /* b. Else */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO_LONG structure */ + /* c. Set wrappedKey -> pcrInfo to keyInfo -> pcrInfo */ + /* d. Set wrappedKey -> digestAtCreation to the TPM_COMPOSITE_HASH indicated by + creationPCRSelection */ + /* e. If V1 is 2 set wrappedKey -> localityAtCreation to TPM_STANY_DATA -> locality */ + /* NOTE Done by TPM_Key_GenerateRSA() */ + /* 16. Encrypt the private portions of the wrappedKey structure using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GenerateEncData(&wrappedKey, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateWrapKey: 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; + /* 17. Return the newly generated key in the wrappedKey parameter */ + returnCode = TPM_Key_Store(response, &wrappedKey); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* cleanup */ + TPM_Key_Delete(&keyInfo); /* @1 */ + TPM_Key_Delete(&wrappedKey); /* @2 */ + TPM_PCRInfo_Delete(&wrappedPCRInfo); /* @3 */ + return rcf; +} + +/* 27.8 TPM_LoadKey rev 114 + + Version 1.2 deprecates LoadKey due to the HMAC of the new keyhandle on return. The wrapping makes + use of the handle difficult in an environment where the TSS, or other management entity, is + changing the TPM handle to a virtual handle. + + Software using loadKey on a 1.2 TPM can have a collision with the returned handle as the 1.2 TPM + uses random values in the lower three bytes of the handle. All new software must use LoadKey2 to + allow management software the ability to manage the key handle. + + Before the TPM can use a key to either wrap, unwrap, bind, unbind, seal, unseal, sign or perform + any other action, it needs to be present in the TPM. The TPM_LoadKey function loads the key into + the TPM for further use. +*/ + +TPM_RESULT TPM_Process_LoadKey(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; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization 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_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + 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; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey: inKey n", inKey->pubKey.buffer); + } + /* 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, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey: 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 + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /*uninitialized*/ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + /* 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, /* 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 + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey 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, inKeyHandle); + } + } + return rcf; +} + +/* 10.5 TPM_LoadKey2 rev 107 + + Before the TPM can use a key to either wrap, unwrap, unbind, seal, unseal, sign or perform any + other action, it needs to be present in the TPM. The TPM_LoadKey2 function loads the key into + the TPM for further use. + + The TPM assigns the key handle. The TPM always locates a loaded key by use of the handle. The + assumption is that the handle may change due to key management operations. It is the + responsibility of upper level software to maintain the mapping between handle and any label used + by external software. + + This command has the responsibility of enforcing restrictions on the use of keys. For example, + when attempting to load a STORAGE key it will be checked for the restrictions on a storage key + (2048 size etc.). + + The load command must maintain a record of whether any previous key in the key hierarchy was + bound to a PCR using parentPCRStatus. + + The flag parentPCRStatus enables the possibility of checking that a platform passed through some + particular state or states before finishing in the current state. A grandparent key could be + linked to state-1, a parent key could linked to state-2, and a child key could be linked to + state-3, for example. The use of the child key then indicates that the platform passed through + states 1 and 2 and is currently in state 3, in this example. TPM_Startup with stType == + TPM_ST_CLEAR indicates that the platform has been reset, so the platform has not passed through + the previous states. Hence keys with parentPCRStatus==TRUE must be unloaded if TPM_Startup is + issued with stType == TPM_ST_CLEAR. + + If a TPM_KEY structure has been decrypted AND the integrity test using "pubDataDigest" has passed + AND the key is non-migratory, the key must have been created by the TPM. So there is every reason + to believe that the key poses no security threat to the TPM. While there is no known attack from + a rogue migratory key, there is a desire to verify that a loaded migratory key is a real key, + arising from a general sense of unease about execution of arbitrary data as a key. Ideally a + consistency check would consist of an encrypt/decrypt cycle, but this may be expensive. For RSA + keys, it is therefore suggested that the consistency test consists of dividing the supposed RSA + product by the supposed RSA prime, and checking that there is no remainder. +*/ + +TPM_RESULT TPM_Process_LoadKey2(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; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization 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_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey2: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + 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; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey2: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey2: inKey n", inKey->pubKey.buffer); + } + /* 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, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey2: 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 + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /* uninitialized */ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey2: 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; + /* In TPM_LoadKey2, the inKeyHandle is not part of the output HMAC */ + /* return the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + } + /* 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, /* 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 + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey 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, inKeyHandle); + } + } + return rcf; +} + +/* TPM_LoadKeyCommon rev 114 + + Code common to TPM_LoadKey and TPM_LoadKey2. They differ only in whether the key handle is + included in the response HMAC calculation. +*/ + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, /* output */ + TPM_BOOL *key_added, /* output */ + TPM_SECRET **hmacKey, /* output */ + TPM_AUTH_SESSION_DATA **auth_session_data, /* output */ + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth) +{ + TPM_RESULT rc = 0; + TPM_KEY *parentKey; /* the key specified by parentHandle */ + TPM_SECRET *parentUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_BOOL parentPCRUsage; + int ver; + + printf("TPM_LoadKeyCommon:\n"); + *key_added = FALSE; /* key has been added to handle list */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (rc == TPM_SUCCESS) { + rc = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_LoadKeyCommon: Error, authorization required\n"); + rc = TPM_AUTHFAIL; + } + } + /* get parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_AuthSessions_GetData(auth_session_data, + hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the command and the parameters using parentAuth and parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Authdata_Check(tpm_state, + **hmacKey, /* HMAC key */ + inParamDigest, + *auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If parentHandle -> keyUsage is NOT TPM_KEY_STORAGE return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_LoadKeyCommon: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* 3. If the TPM is not designed to operate on a key of the type specified by inKey, return the + error code TPM_BAD_KEY_PROPERTY. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckProperties(&ver, inKey, 0, tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_LoadKeyCommon: key parameters v = %d\n", ver); + } + /* 4. The TPM MUST handle both TPM_KEY and TPM_KEY12 structures. + This step is done at TPM_Key_Load() + */ + /* 5. Decrypt the inKey -> privkey to obtain TPM_STORE_ASYMKEY structure using the key in + parentHandle. + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_DecryptEncData(inKey, parentKey); + } + /* 6. Validate the integrity of inKey and decrypted TPM_STORE_ASYMKEY + a. Reproduce inKey -> TPM_STORE_ASYMKEY -> pubDataDigest using the fields of inKey, and check + that the reproduced value is the same as pubDataDigest + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckPubDataDigest(inKey); + } + /* 7. Validate the consistency of the key and it's key usage. */ + /* a. If inKey -> keyFlags -> migratable is TRUE, the TPM SHALL verify consistency of the public + and private components of the asymmetric key pair. If inKey -> keyFlags -> migratable is + FALSE, the TPM MAY verify consistency of the public and private components of the asymmetric + key pair. The consistency of an RSA key pair MAY be verified by dividing the supposed (P*Q) + product by a supposed prime and checking that there is no remainder. + + This step is done at TPM_Key_Load() + */ + /* b. If inKey -> keyUsage is TPM_KEY_IDENTITY, verify that inKey->keyFlags->migratable is + FALSE. If it is not, return TPM_INVALID_KEYUSAGE + */ + if (rc == TPM_SUCCESS) { + if ((inKey->keyUsage == TPM_KEY_IDENTITY) && + (inKey->keyFlags & TPM_MIGRATABLE)) { + printf("TPM_LoadKeyCommon: Error, identity key is migratable\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* c. If inKey -> keyUsage is TPM_KEY_AUTHCHANGE, return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (inKey->keyUsage == TPM_KEY_AUTHCHANGE) { + printf("TPM_LoadKeyCommon: Error, keyUsage is TPM_KEY_AUTHCHANGE\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* d. If inKey -> keyFlags -> migratable equals 0 then verify that TPM_STORE_ASYMKEY -> + migrationAuth equals TPM_PERMANENT_DATA -> tpmProof */ + if (rc == TPM_SUCCESS) { + if (!(inKey->keyFlags & TPM_MIGRATABLE)) { + rc = TPM_Secret_Compare(tpm_state->tpm_permanent_data.tpmProof, + inKey->tpm_store_asymkey->migrationAuth); + if (rc != 0) { + printf("TPM_LoadKeyCommon: Error, tpmProof mismatch\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + /* e. Validate the mix of encryption and signature schemes + f. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + i. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + ii. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return + TPM_NOTFIPS + iii. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return + TPM_NOTFIPS + g. If inKey -> keyUsage is TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iii. exponentSize MUST be 0 + iv. sigScheme MUST be TPM_SS_NONE + h. If inKey -> keyUsage is TPM_KEY_IDENTITY + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iv. exponentSize MUST be 0 + iii. encScheme MUST be TPM_ES_NONE + NOTE Done in step 3. + */ + if (rc == TPM_SUCCESS) { + /* i. If the decrypted inKey -> pcrInfo is NULL, */ + /* i. The TPM MUST set the internal indicator to indicate that the key is not using any PCR + registers. */ + /* j. Else */ + /* i. The TPM MUST store pcrInfo in a manner that allows the TPM to calculate a composite + hash whenever the key will be in use */ + /* ii. The TPM MUST handle both version 1.1 TPM_PCR_INFO and 1.2 TPM_PCR_INFO_LONG + structures according to the type of TPM_KEY structure */ + /* (1) The TPM MUST validate the TPM_PCR_INFO or TPM_PCR_INFO_LONG structures for legal + values. However, the digestAtRelease and localityAtRelease are not validated for + authorization until use time.*/ + /* NOTE TPM_Key_Load() loads the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + } + /* 8. Perform any processing necessary to make TPM_STORE_ASYMKEY key available for + operations. */ + /* NOTE Done at TPM_Key_Load() */ + /* 9. Load key and key information into internal memory of the TPM. If insufficient memory + exists return error TPM_NOSPACE. */ + /* 10. Assign inKeyHandle according to internal TPM rules. */ + /* 11. Set InKeyHandle -> parentPCRStatus to parentHandle -> parentPCRStatus. */ + if (rc == TPM_SUCCESS) { + *inKeyHandle = 0; /* no preferred value */ + rc = TPM_KeyHandleEntries_AddKeyEntry(inKeyHandle, /* output */ + tpm_state->tpm_key_handle_entries, /* input */ + inKey, /* input */ + parentPCRStatus, + 0); /* keyControl */ + } + if (rc == TPM_SUCCESS) { + printf(" TPM_LoadKeyCommon: Loaded key handle %08x\n", *inKeyHandle); + /* remember that the handle has been added to handle list, so it can be deleted on error */ + *key_added = TRUE; + + } + /* 12. If parentHandle indicates it is using PCR registers then set inKeyHandle -> + parentPCRStatus to TRUE. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_GetPCRUsage(&parentPCRUsage, parentKey, 0); + } + if (rc == TPM_SUCCESS) { + if (parentPCRUsage) { + rc = TPM_KeyHandleEntries_SetParentPCRStatus(tpm_state->tpm_key_handle_entries, + *inKeyHandle, TRUE); + } + } + return rc; +} + +/* 10.6 TPM_GetPubKey rev 102 + + The owner of a key may wish to obtain the public key value from a loaded key. This information + may have privacy concerns so the command must have authorization from the key owner. +*/ + +TPM_RESULT TPM_Process_GetPubKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* TPM handle of key. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /*The continue use flag for the authorization + handle */ + TPM_AUTHDATA keyAuth; /* Authorization HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_STORE_BUFFER pubkeyStream; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + const unsigned char *pubkeyStreamBuffer; /* output */ + uint32_t pubkeyStreamLength; + + printf("TPM_Process_GetPubKey: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: keyHandle %08x\n", keyHandle); + } + /* 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, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetPubKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: Key handle %08x\n", keyHandle); + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* 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, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + + + /* a. Validate the command parameters using keyHandle -> usageAuth, on error return + TPM_AUTHFAIL */ + 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, + keyAuth); /* Authorization digest for input */ + } + /* 2. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + /* a. Verify that keyHandle -> authDataUsage is TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER, + on error return TPM_AUTHFAIL */ +#ifdef TPM_V12 + if ((key->authDataUsage != TPM_NO_READ_PUBKEY_AUTH) && + (key->authDataUsage != TPM_AUTH_NEVER)) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#else /* TPM 1.1 does not have TPM_NO_READ_PUBKEY_AUTH */ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#endif + } +#ifdef TPM_V12 /* TPM 1.1 does not have readSRKPub */ + if (returnCode == TPM_SUCCESS) { + /* 3. If keyHandle == TPM_KH_SRK then */ + if ((keyHandle == TPM_KH_SRK) && + /* a. If TPM_PERMANENT_FLAGS -> readSRKPub is FALSE then return TPM_INVALID_KEYHANDLE */ + !tpm_state->tpm_permanent_flags.readSRKPub) { + printf("TPM_Process_GetPubKey: " + "Error, keyHandle is TPM_KH_SRK and readSRKPub is FALSE\n"); + returnCode = TPM_INVALID_KEYHANDLE; + } + } +#endif + /* 4. If keyHandle -> pcrInfoSize is not 0 */ + /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and compare + to keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests */ + /* NOTE: Done at TPM_KeyHandleEntries_GetKey() */ + /* 5. Create a TPM_PUBKEY structure and return */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + key); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetPubKey: 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; + /* TPM_PUBKEY structure */ + returnCode = TPM_Sbuffer_Append(response, pubkeyStreamBuffer, pubkeyStreamLength); + /* 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_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rcf; +} diff --git a/src/tpm12/tpm_storage.h b/src/tpm12/tpm_storage.h new file mode 100644 index 0000000..060e44f --- /dev/null +++ b/src/tpm12/tpm_storage.h @@ -0,0 +1,167 @@ +/********************************************************************************/ +/* */ +/* Storage Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_storage.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_STORAGE_H +#define TPM_STORAGE_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + TPM_BOUND_DATA +*/ + +void TPM_BoundData_Init(TPM_BOUND_DATA *tpm_bound_data); +TPM_RESULT TPM_BoundData_Load(TPM_BOUND_DATA *tpm_bound_data, + unsigned char **stream, + uint32_t *stream_size); +#if 0 +TPM_RESULT TPM_BoundData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_BOUND_DATA *tpm_bound_data); +#endif +void TPM_BoundData_Delete(TPM_BOUND_DATA *tpm_bound_data); + +/* + TPM_SEALED_DATA +*/ + +void TPM_SealedData_Init(TPM_SEALED_DATA *tpm_sealed_data); +TPM_RESULT TPM_SealedData_Load(TPM_SEALED_DATA *tpm_sealed_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SealedData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SEALED_DATA *tpm_sealed_data); +void TPM_SealedData_Delete(TPM_SEALED_DATA *tpm_sealed_data); + +TPM_RESULT TPM_SealedData_DecryptEncData(TPM_SEALED_DATA *tpm_sealed_data, + TPM_SIZED_BUFFER *enc_data, + TPM_KEY *tpm_key); +TPM_RESULT TPM_SealedData_GenerateEncData(TPM_SIZED_BUFFER *enc_data, + const TPM_SEALED_DATA *tpm_sealed_data, + TPM_KEY *tpm_key); + +/* + TPM_STORED_DATA +*/ + +void TPM_StoredData_Init(TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +TPM_RESULT TPM_StoredData_Load(TPM_STORED_DATA *tpm_stored_data, + unsigned int *version, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StoredData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +void TPM_StoredData_Delete(TPM_STORED_DATA *tpm_stored_data, + unsigned int version); + +TPM_RESULT TPM_StoredData_CheckTag(TPM_STORED_DATA12 *tpm_stored_data12); +TPM_RESULT TPM_StoredData_StoreClearData(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +TPM_RESULT TPM_StoredData_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_Seal(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 TPM_Process_Sealx(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 TPM_Process_Unseal(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 TPM_Process_UnBind(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 TPM_Process_CreateWrapKey(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 TPM_Process_LoadKey(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 TPM_Process_LoadKey2(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 TPM_Process_GetPubKey(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); + + + +#endif diff --git a/src/tpm12/tpm_store.c b/src/tpm12/tpm_store.c new file mode 100644 index 0000000..ce79190 --- /dev/null +++ b/src/tpm12/tpm_store.c @@ -0,0 +1,598 @@ +/********************************************************************************/ +/* */ +/* Safe Storage Buffer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_store.c 4668 2012-01-25 21:16:48Z 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. */ +/********************************************************************************/ + +/* Generally useful utilities to serialize structures to a stream */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "tpm_commands.h" +#include "tpm_constants.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_memory.h" +#include "tpm_process.h" + +#include "tpm_store.h" + +/* + ->buffer; beginning of buffer + ->buffer_current; first empty position in buffer + ->buffer_end; one past last valid position in buffer +*/ + +/* local prototypes */ + +static void TPM_Sbuffer_AdjustParamSize(TPM_STORE_BUFFER *sbuffer); +static TPM_RESULT TPM_Sbuffer_AdjustReturnCode(TPM_STORE_BUFFER *sbuffer, TPM_RESULT returnCode); + + +/* TPM_Sbuffer_Init() sets up a new serialize buffer. It should be called before the first use. */ + +void TPM_Sbuffer_Init(TPM_STORE_BUFFER *sbuffer) +{ + sbuffer->buffer = NULL; + sbuffer->buffer_current = NULL; + sbuffer->buffer_end = NULL; +} + +/* TPM_Sbuffer_Load() loads TPM_STORE_BUFFER that has been serialized using + TPM_Sbuffer_AppendAsSizedBuffer(), as a size plus stream. +*/ + +TPM_RESULT TPM_Sbuffer_Load(TPM_STORE_BUFFER *sbuffer, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t length; + + /* get the length of the stream to be loaded */ + if (rc == 0) { + rc = TPM_Load32(&length, stream, stream_size); + } + /* check stream_size */ + if (rc == 0) { + if (*stream_size < length) { + printf("TPM_Sbuffer_Load: Error, stream_size %u less than %u\n", + *stream_size, length); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, *stream, length); + *stream += length; + *stream_size -= length; + } + return rc; +} + +/* TPM_Sbuffer_Store() cannot simply store the elements, as they are pointers. Rather, the + TPM_Sbuffer_AppendAsSizedBuffer() function is used. +*/ + +/* TPM_Sbuffer_Delete() frees an existing buffer and reinitializes it. It must be called when a + TPM_STORE_BUFFER is no longer required, to avoid a memory leak. The buffer can be reused, but in + that case TPM_Sbuffer_Clear would be a better choice. */ + +void TPM_Sbuffer_Delete(TPM_STORE_BUFFER *sbuffer) +{ + free(sbuffer->buffer); + TPM_Sbuffer_Init(sbuffer); +} + +/* TPM_Sbuffer_Clear() removes all data from an existing buffer, allowing reuse. Memory is NOT + freed. */ + +void TPM_Sbuffer_Clear(TPM_STORE_BUFFER *sbuffer) +{ + sbuffer->buffer_current = sbuffer->buffer; + return; +} + +/* TPM_Sbuffer_Get() gets the resulting byte buffer and its size. */ + +void TPM_Sbuffer_Get(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length) +{ + *length = sbuffer->buffer_current - sbuffer->buffer; + *buffer = sbuffer->buffer; + return; +} + +/* TPM_Sbuffer_GetAll() gets the resulting byte buffer and its size, as well as the total size. */ + +void TPM_Sbuffer_GetAll(TPM_STORE_BUFFER *sbuffer, + unsigned char **buffer, + uint32_t *length, + uint32_t *total) +{ + *length = sbuffer->buffer_current - sbuffer->buffer; + *total = sbuffer->buffer_end - sbuffer->buffer; + *buffer = sbuffer->buffer; + return; +} + +/* TPM_Sbuffer_Set() creates a TPM_STORE_BUFFER from + + 'buffer' - pointer to a buffer that was allocated (can be NULL) + + 'total' - the total number of allocated bytes (ignored if buffer is NULL) + + 'length' - the number of valid bytes in buffer (ignored if buffer is NULL, can be 0, cannot be + greater than total. +*/ + +TPM_RESULT TPM_Sbuffer_Set(TPM_STORE_BUFFER *sbuffer, + unsigned char *buffer, + const uint32_t length, + const uint32_t total) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (sbuffer == NULL) { + printf("TPM_Sbuffer_Set: Error (fatal), sbuffer is NULL\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (buffer != NULL) { + if (rc == 0) { + if (length > total) { + printf("TPM_Sbuffer_Set: Error (fatal), length %u > total %u\n", + length, total); + rc = TPM_FAIL; + } + } + if (rc == 0) { + sbuffer->buffer = buffer; + sbuffer->buffer_current = buffer + length; + sbuffer->buffer_end = buffer + total; + } + } + else { /* buffer == NULL */ + sbuffer->buffer = NULL; + sbuffer->buffer_current = NULL; + sbuffer->buffer_end = NULL; + } + } + return rc; +} + +/* TPM_Sbuffer_Append() is the basic function to append 'data' of size 'data_length' to the + TPM_STORE_BUFFER + + Returns 0 if success, TPM_SIZE if the buffer cannot be allocated. +*/ + +TPM_RESULT TPM_Sbuffer_Append(TPM_STORE_BUFFER *sbuffer, + const unsigned char *data, + size_t data_length) +{ + TPM_RESULT rc = 0; + size_t free_length; /* length of free bytes in current buffer */ + size_t current_size; /* size of current buffer */ + size_t current_length; /* bytes in current buffer */ + size_t new_size; /* size of new buffer */ + + /* can data fit? */ + if (rc == 0) { + /* cast safe as end is always greater than current */ + free_length = (size_t)(sbuffer->buffer_end - sbuffer->buffer_current); + /* if data cannot fit in buffer as sized */ + if (free_length < data_length) { + /* This test will fail long before the add uint32_t overflow */ + if (rc == 0) { + /* cast safe as current is always greater than start */ + current_length = (size_t)(sbuffer->buffer_current - sbuffer->buffer); + if ((current_length + data_length) > TPM_ALLOC_MAX) { + printf("TPM_Sbuffer_Append: " + "Error, size %lu + %lu greater than maximum allowed\n", + (unsigned long)current_length, (unsigned long)data_length); + rc = TPM_SIZE; + } + } + if (rc == 0) { + /* cast safe as end is always greater than start */ + current_size = (size_t)(sbuffer->buffer_end - sbuffer->buffer); + /* optimize realloc's by rounding up data_length to the next increment */ + new_size = current_size + /* currently used */ + ((((data_length - 1)/TPM_STORE_BUFFER_INCREMENT) + 1) * + TPM_STORE_BUFFER_INCREMENT); + /* but not greater than maximum buffer size */ + if (new_size > TPM_ALLOC_MAX) { + new_size = TPM_ALLOC_MAX; + } + printf(" TPM_Sbuffer_Append: data_length %lu, growing from %lu to %lu\n", + (unsigned long)data_length, + (unsigned long)current_size, + (unsigned long)new_size); + rc = TPM_Realloc(&(sbuffer->buffer), new_size); + } + if (rc == 0) { + sbuffer->buffer_end = sbuffer->buffer + new_size; /* end */ + sbuffer->buffer_current = sbuffer->buffer + current_length; /* new empty position */ + } + } + } + /* append the data */ + if (rc == 0) { + if (data_length > 0) { /* libtpms added (ubsan) */ + memcpy(sbuffer->buffer_current, data, data_length); + sbuffer->buffer_current += data_length; + } + } + return rc; +} + +/* TPM_Sbuffer_Append8() is a special append that appends a uint8_t + */ + +TPM_RESULT TPM_Sbuffer_Append8(TPM_STORE_BUFFER *sbuffer, uint8_t data) +{ + TPM_RESULT rc = 0; + + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&data), sizeof(uint8_t)); + return rc; +} + +/* TPM_Sbuffer_Append16() is a special append that converts a uint16_t to big endian (network byte + order) and appends. */ + +TPM_RESULT TPM_Sbuffer_Append16(TPM_STORE_BUFFER *sbuffer, uint16_t data) +{ + TPM_RESULT rc = 0; + + uint16_t ndata = htons(data); + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&ndata), sizeof(uint16_t)); + return rc; +} + +/* TPM_Sbuffer_Append32() is a special append that converts a uint32_t to big endian (network byte + order) and appends. */ + +TPM_RESULT TPM_Sbuffer_Append32(TPM_STORE_BUFFER *sbuffer, uint32_t data) +{ + TPM_RESULT rc = 0; + + uint32_t ndata = htonl(data); + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&ndata), sizeof(uint32_t)); + return rc; +} + +/* TPM_Sbuffer_AppendAsSizedBuffer() appends the source to the destination using the + TPM_SIZED_BUFFER idiom. That is, for a uint32_t size is stored. Then the data is stored. + + Use this function when the stream is not self-describing and a size must be prepended. +*/ + +TPM_RESULT TPM_Sbuffer_AppendAsSizedBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + if (rc == 0) { + TPM_Sbuffer_Get(srcSbuffer, &buffer, &length); + rc = TPM_Sbuffer_Append32(destSbuffer, length); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(destSbuffer, buffer, length); + } + return rc; +} + +/* TPM_Sbuffer_AppendSBuffer() appends the source to the destination. The size is not prepended, so + the stream must be self-describing. +*/ + +TPM_RESULT TPM_Sbuffer_AppendSBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + if (rc == 0) { + TPM_Sbuffer_Get(srcSbuffer, &buffer, &length); + rc = TPM_Sbuffer_Append(destSbuffer, buffer, length); + } + return rc; +} + +/* TPM_Sbuffer_StoreInitialResponse() is a special purpose append specific to a TPM response. + + It appends the first 3 standard response parameters: + - response_tag + - parameter size + - return code + + For some TPM commands, this is the entire response. Other times, additional parameters + will be appended. See TPM_Sbuffer_StoreFinalResponse(). + + Returns: + 0 success + TPM_SIZE response could not fit in buffer +*/ + +TPM_RESULT TPM_Sbuffer_StoreInitialResponse(TPM_STORE_BUFFER *response, + TPM_TAG request_tag, + TPM_RESULT returnCode) +{ + TPM_RESULT rc = 0; + TPM_TAG response_tag; + + printf(" TPM_Sbuffer_StoreInitialResponse: returnCode %08x\n", returnCode); + if (rc == 0) { + if (request_tag == TPM_TAG_RQU_COMMAND) { + response_tag = TPM_TAG_RSP_COMMAND; + } + else if (request_tag == TPM_TAG_RQU_AUTH1_COMMAND) { + response_tag = TPM_TAG_RSP_AUTH1_COMMAND; + } + else if (request_tag == TPM_TAG_RQU_AUTH2_COMMAND) { + response_tag = TPM_TAG_RSP_AUTH2_COMMAND; + } + /* input tag error, returnCode is handled by caller TPM_CheckRequestTag() */ + else { + response_tag = TPM_TAG_RSP_COMMAND; + } + } + /* tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(response, response_tag); + } + /* paramSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(response, + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)); + } + /* returnCode */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(response, returnCode); + } + return rc; +} + +/* TPM_Sbuffer_StoreFinalResponse() is a special purpose append specific to a TPM response. + + It is used after TPM_Sbuffer_StoreInitialResponse() and all additional parameters are appended. + + 1 - If the additional parameters were successfully appended, this function adjusts the + preliminary parameter size set by TPM_Sbuffer_StoreInitialResponse() to reflect the additional + appends. + + 2 - If there was a failure during the additional appends, this function adjusts the return code + and removes the additional appends. +*/ + +TPM_RESULT TPM_Sbuffer_StoreFinalResponse(TPM_STORE_BUFFER *sbuffer, + TPM_RESULT returnCode, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_Sbuffer_StoreFinalResponse: returnCode %08x\n", returnCode); + /* determine whether the response would exceed the output buffer size */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + if (length > TPM12_GetBufferSize()) { + printf("TPM_Sbuffer_StoreFinalResponse: Error, response buffer %u exceeds max %u\n", + length, TPM12_GetBufferSize()); + returnCode = TPM_SIZE; + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_AdjustParamSize(sbuffer); + } + else { + /* TPM_FAIL is reserved for "should never occur" errors that indicate a software or hardware + failure */ + if ((returnCode == TPM_FAIL) && (tpm_state != NULL)) { + printf(" TPM_Sbuffer_StoreFinalResponse: Set testState to %u \n", + TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + rc = TPM_Sbuffer_AdjustReturnCode(sbuffer, returnCode); + } + return rc; +} + +/* TPM_Sbuffer_AdjustParamSize() is a special purpose function to go back and adjust the response + paramSize after the response buffer is complete +*/ + +static void TPM_Sbuffer_AdjustParamSize(TPM_STORE_BUFFER *sbuffer) +{ + uint32_t paramSize; /* the correct paramsize */ + uint32_t nParamSize; /* the correct paramsize, in network byte order */ + uint32_t paramSizeOffset; + + /* actual size */ + paramSize = sbuffer->buffer_current - sbuffer->buffer; + paramSizeOffset = sizeof(TPM_TAG); + nParamSize = htonl(paramSize); /* network byte order */ + /* overwrite the original size */ + memcpy(sbuffer->buffer + paramSizeOffset, &nParamSize, sizeof(uint32_t)); + return; +} + +/* TPM_Sbuffer_AdjustReturnCode() is a special function to go back and adjust the response tag and + returnCode if there was a failure while appending the rest of the parameters. + + This should never fail, because sbuffer was allocated during TPM_Sbuffer_StoreInitialResponse(). +*/ + +static TPM_RESULT TPM_Sbuffer_AdjustReturnCode(TPM_STORE_BUFFER *sbuffer, TPM_RESULT returnCode) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + /* erase the previous result without freeing the buffer */ + sbuffer->buffer_current = sbuffer->buffer; + /* error tag */ + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_RSP_COMMAND); + } + /* paramSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)); + } + /* returnCode */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, returnCode); + } + return rc; +} + +#if 0 +/* Test appending to the TPM_STORE_BUFFER up to the limit */ + +TPM_RESULT TPM_Sbuffer_Test(void) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + size_t total_count; + unsigned char count; + unsigned char data[256]; /* dummy data */ + + printf(" TPM_Sbuffer_Test:\n"); + TPM_Sbuffer_Init(&sbuffer); + total_count = 0; + while ((total_count != TPM_ALLOC_MAX) && rc == 0) { + if (rc == 0) { + rc = TPM_Random(&count, 1); + } + if (rc == 0) { + printf(" TPM_Sbuffer_Test: count %u\n", count); + /* last time through */ + if (total_count + count > TPM_ALLOC_MAX) { + count = TPM_ALLOC_MAX - total_count; + } + rc = TPM_Sbuffer_Append(&sbuffer,data, count); + } + if (rc == 0) { + total_count += count; + } + printf(" TPM_Sbuffer_Test: total_count %lu\n", (unsigned long)total_count); + } + TPM_Sbuffer_Delete(&sbuffer); + return rc; +} +#endif + +/* type to byte stream */ +void STORE32(unsigned char *buffer, unsigned int offset, uint32_t value) +{ + buffer[offset + 0] = value >> 24; + buffer[offset + 1] = value >> 16; + buffer[offset + 2] = value >> 8; + buffer[offset + 3] = value >> 0; +} + +void STORE16(unsigned char *buffer, unsigned int offset, uint16_t value) +{ + buffer[offset + 0] = value >> 8; + buffer[offset + 1] = value >> 0; +} + +void STORE8(unsigned char *buffer, unsigned int offset, uint8_t value) + +{ + buffer[offset + 0] = value >> 0; +} + +/* TPM_Bitmap_Load() is a safe loading of a TPM_BOOL from a bitmap. + + If 'pos' is >= 32, the function fails. + TPM_BOOL is TRUE. if The bit at pos is set + 'pos' is incremented after the load. +*/ + +TPM_RESULT TPM_Bitmap_Load(TPM_BOOL *tpm_bool, + uint32_t tpm_bitmap, + uint32_t *pos) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if ((*pos) >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_Bitmap_Load: Error (fatal), loading from position %u\n", *pos); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + *tpm_bool = (tpm_bitmap & (1 << (*pos))) != 0; + (*pos)++; + } + return rc; +} + +/* TPM_Bitmap_Store() is a safe storing of a TPM_BOOL into a bitmap. + + If 'pos' is >= 32, the function fails. + The bit at pos is set if the TPM_BOOL is TRUE. + 'pos' is incremented after the store. +*/ + +TPM_RESULT TPM_Bitmap_Store(uint32_t *tpm_bitmap, + TPM_BOOL tpm_bool, + uint32_t *pos) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if ((*pos) >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_Bitmap_Store: Error (fatal), storing to position %u\n", *pos); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + if (tpm_bool) { + *tpm_bitmap |= (1 << (*pos)); + } + (*pos)++; + } + return rc; +} + diff --git a/src/tpm12/tpm_store.h b/src/tpm12/tpm_store.h new file mode 100644 index 0000000..8b6fefd --- /dev/null +++ b/src/tpm12/tpm_store.h @@ -0,0 +1,111 @@ +/********************************************************************************/ +/* */ +/* Safe Storage Buffer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_store.h 4668 2012-01-25 21:16:48Z 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. */ +/********************************************************************************/ + +#ifndef TPM_STORE_H +#define TPM_STORE_H + +#include "tpm_global.h" +#include "tpm_load.h" +#include "tpm_types.h" + +void TPM_Sbuffer_Init(TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_Sbuffer_Load(TPM_STORE_BUFFER *sbuffer, + unsigned char **stream, + uint32_t *stream_size); +/* TPM_Sbuffer_Store(): See TPM_Sbuffer_AppendAsSizedBuffer() */ +void TPM_Sbuffer_Delete(TPM_STORE_BUFFER *sbuffer); + +void TPM_Sbuffer_Clear(TPM_STORE_BUFFER *sbuffer); +void TPM_Sbuffer_Get(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length); +void TPM_Sbuffer_GetAll(TPM_STORE_BUFFER *sbuffer, + unsigned char **buffer, + uint32_t *length, + uint32_t *total); +TPM_RESULT TPM_Sbuffer_Set(TPM_STORE_BUFFER *sbuffer, + unsigned char *buffer, + const uint32_t length, + const uint32_t total); + +TPM_RESULT TPM_Sbuffer_Append(TPM_STORE_BUFFER *sbuffer, + const unsigned char *data, + size_t data_length); + +TPM_RESULT TPM_Sbuffer_Append8(TPM_STORE_BUFFER *sbuffer, uint8_t data); +TPM_RESULT TPM_Sbuffer_Append16(TPM_STORE_BUFFER *sbuffer, uint16_t data); +TPM_RESULT TPM_Sbuffer_Append32(TPM_STORE_BUFFER *sbuffer, uint32_t data); +TPM_RESULT TPM_Sbuffer_AppendAsSizedBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer); +TPM_RESULT TPM_Sbuffer_AppendSBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer); + + +TPM_RESULT TPM_Sbuffer_StoreInitialResponse(TPM_STORE_BUFFER *response, + TPM_TAG response_tag, + TPM_RESULT returnCode); +TPM_RESULT TPM_Sbuffer_StoreFinalResponse(TPM_STORE_BUFFER *sbuffer, + TPM_RESULT returnCode, + tpm_state_t *tpm_state); + +#if 0 +TPM_RESULT TPM_Sbuffer_Test(void); +#endif + +/* type to byte stream */ + +void STORE32(unsigned char *buffer, unsigned int offset, uint32_t value); +void STORE16(unsigned char *buffer, unsigned int offset, uint16_t value); +void STORE8 (unsigned char *buffer, unsigned int offset, uint8_t value); + +/* load and store to bitmap */ + +TPM_RESULT TPM_Bitmap_Load(TPM_BOOL *tpm_bool, + uint32_t tpm_bitmap, + uint32_t *pos); +TPM_RESULT TPM_Bitmap_Store(uint32_t *tpm_bitmap, + TPM_BOOL tpm_bool, + uint32_t *pos); + +/* generic function prototype for a structure store callback function */ + +typedef TPM_RESULT (*TPM_STORE_FUNCTION_T )(TPM_STORE_BUFFER *sbuffer, + const void *tpm_structure); + +#endif diff --git a/src/tpm12/tpm_structures.h b/src/tpm12/tpm_structures.h new file mode 100644 index 0000000..1552126 --- /dev/null +++ b/src/tpm12/tpm_structures.h @@ -0,0 +1,2630 @@ +/********************************************************************************/ +/* */ +/* TPM Structures */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_structures.h 4528 2011-03-29 22:16:28Z 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. */ +/********************************************************************************/ + +#ifndef TPM_STRUCTURES_H +#define TPM_STRUCTURES_H + +#include <limits.h> +#include "tpm_constants.h" +#include "tpm_memory.h" +#include "tpm_types.h" +#include "tpm_nvram_const.h" + +/* Sanity check on build macros are centralized here, since any TPM will use this header */ + +#if !defined (TPM_POSIX) && !defined (TPM_WINDOWS) && !defined(TPM_SYSTEM_P) +#error "Must define either TPM_POSIX or TPM_WINDOWS or TPM_SYSTEM_P" +#endif + +#if defined (TPM_NV_XCRYPTO_FLASH) && defined (TPM_NV_DISK) +#error "Cannot define TPM_NV_XCRYPTO_FLASH and TPM_NV_DISK" +#endif + +#if defined (TPM_WINDOWS) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_WINDOWS and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_USE_CHARDEV) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_USE_CHARDEV and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_NV_XCRYPTO_FLASH) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_NV_XCRYPTO_FLASH and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_XCRYPTO_USE_HW) && !defined(TPM_NV_XCRYPTO_FLASH) +#error "TPM_XCRYPTO_USE_HW requires TPM_NV_XCRYPTO_FLASH" +#endif + +#if defined (TPM_VTPM) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_VTPM and TPM_UNIX_DOMAIN_SOCKET" +#endif + + + +#if defined (TPM_V11) && defined (TPM_V12) +#error "Cannot define TPM_V12 and TPM_V11" +#endif + +#if !defined (TPM_V11) && !defined (TPM_V12) +#error "Must define either TPM_V12 or TPM_V11" +#endif + +#if defined (TPM_DES) && defined (TPM_AES) +#error "Cannot define TPM_DES and TPM_AES" +#endif +#if !defined (TPM_DES) && !defined (TPM_AES) +#error "Must define either TPM_DES or TPM_AES" +#endif + +/* This structure is typically a cast from a subset of a larger TPM structure. Two members - a 4 + bytes size followed by a 4 bytes pointer to the data is a common TPM structure idiom. */ + +typedef struct tdTPM_SIZED_BUFFER { + uint32_t size; + BYTE *buffer; +} TPM_SIZED_BUFFER; + +/* This structure implements a safe storage buffer, used throughout the code when serializing + structures to a stream. +*/ + +typedef struct tdTPM_STORE_BUFFER { + unsigned char *buffer; /* beginning of buffer */ + unsigned char *buffer_current; /* first empty position in buffer */ + unsigned char *buffer_end; /* one past last valid position in buffer */ +} TPM_STORE_BUFFER; + +/* 5.1 TPM_STRUCT_VER rev 100 + + This indicates the version of the structure or TPM. + + Version 1.2 deprecates the use of this structure in all other structures. The structure is not + deprecated as many of the structures that contain this structure are not deprecated. +*/ + +#define TPM_MAJOR 0x01 + +#if defined TPM_V12 +#define TPM_MINOR 0x02 +#endif + +#if defined TPM_V11 +#define TPM_MINOR 0x01 +#endif + +typedef struct tdTPM_STRUCT_VER { + BYTE major; /* This SHALL indicate the major version of the structure. MUST be 0x01 */ + BYTE minor; /* This SHALL indicate the minor version of the structure. MUST be 0x01 */ + BYTE revMajor; /* This MUST be 0x00 on output, ignored on input */ + BYTE revMinor; /* This MUST be 0x00 on output, ignored on input */ +} TPM_STRUCT_VER; + +/* 5.2 TPM_VERSION_BYTE rev 87 + + Allocating a byte for the version information is wasteful of space. The current allocation does + not provide sufficient resolution to indicate completely the version of the TPM. To allow for + backwards compatibility the size of the structure does not change from 1.1. + + To enable minor version, or revision, numbers with 2-digit resolution, the byte representing a + version splits into two BDC encoded nibbles. The ordering of the low and high order provides + backwards compatibility with existing numbering. + + An example of an implementation of this is; a version of 1.23 would have the value 2 in bit + positions 3-0 and the value 3 in bit positions 7-4. + + TPM_VERSION_BYTE is a byte. The byte is broken up according to the following rule + + 7-4 leastSigVer Least significant nibble of the minor version. MUST be values within the range of + 0000-1001 + 3-0 mostSigVer Most significant nibble of the minor version. MUST be values within the range of + 0000-1001 +*/ + +/* 5.3 TPM_VERSION rev 116 + + This structure provides information relative the version of the TPM. This structure should only + be in use by TPM_GetCapability to provide the information relative to the TPM. +*/ + +typedef struct tdTPM_VERSION { + TPM_VERSION_BYTE major; /* This SHALL indicate the major version of the TPM, mostSigVer MUST + be 0x1, leastSigVer MUST be 0x0 */ + TPM_VERSION_BYTE minor; /* This SHALL indicate the minor version of the TPM, mostSigVer MUST + be 0x1 or 0x2, leastSigVer MUST be 0x0 */ + BYTE revMajor; /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMajor */ + BYTE revMinor; /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMinor */ +} TPM_VERSION; + +/* 5.4 TPM_DIGEST rev 111 + + The digest value reports the result of a hash operation. + + In version 1 the hash algorithm is SHA-1 with a resulting hash result being 20 bytes or 160 bits. + + It is understood that algorithm agility is lost due to fixing the hash at 20 bytes and on + SHA-1. The reason for fixing is due to the internal use of the digest. It is the authorization + values, it provides the secrets for the HMAC and the size of 20 bytes determines the values that + can be stored and encrypted. For this reason, the size is fixed and any changes to this value + require a new version of the specification. + + The digestSize parameter MUST indicate the block size of the algorithm and MUST be 20 or greater. + + For all TPM v1 hash operations, the hash algorithm MUST be SHA-1 and the digestSize parameter is + therefore equal to 20. +*/ + +#define TPM_DIGEST_SIZE 20 +typedef BYTE TPM_DIGEST[TPM_DIGEST_SIZE]; + +#if 0 +/* kgold - This was designed as a structure with one element. Changed to a simple BYTE array, like + TPM_SECRET. */ +typedef struct tdTPM_DIGEST { + BYTE digest[TPM_DIGEST_SIZE]; /* This SHALL be the actual digest information */ +} TPM_DIGEST; +#endif + +/* Redefinitions */ + +typedef TPM_DIGEST TPM_CHOSENID_HASH; /* This SHALL be the digest of the chosen identityLabel and + privacyCA for a new TPM identity.*/ + +typedef TPM_DIGEST TPM_COMPOSITE_HASH; /* This SHALL be the hash of a list of PCR indexes and PCR + values that a key or data is bound to. */ + +typedef TPM_DIGEST TPM_DIRVALUE; /* This SHALL be the value of a DIR register */ + +typedef TPM_DIGEST TPM_HMAC; /* This shall be the output of the HMAC algorithm */ + +typedef TPM_DIGEST TPM_PCRVALUE; /* The value inside of the PCR */ + +typedef TPM_DIGEST TPM_AUDITDIGEST; /* This SHALL be the value of the current internal audit + state */ + +/* 5.5 TPM_NONCE rev 99 + + A nonce is a random value that provides protection from replay and other attacks. Many of the + commands and protocols in the specification require a nonce. This structure provides a consistent + view of what a nonce is. +*/ + +#define TPM_NONCE_SIZE 20 +typedef BYTE TPM_NONCE[TPM_NONCE_SIZE]; + +#if 0 +/* kgold - This was designed as a structure with one element. Changed to a simple BYTE array, like + TPM_SECRET. */ +typedef struct tdTPM_NONCE { + BYTE nonce[TPM_NONCE_SIZE]; /* This SHALL be the 20 bytes of random data. When created by the + TPM the value MUST be the next 20 bytes from the RNG */ +} TPM_NONCE; +#endif + +typedef TPM_NONCE TPM_DAA_TPM_SEED; /* This SHALL be a random value generated by a TPM + immediately after the EK is installed in that TPM, + whenever an EK is installed in that TPM */ +typedef TPM_NONCE TPM_DAA_CONTEXT_SEED; /* This SHALL be a random value */ + +/* 5.6 TPM_AUTHDATA rev 87 + + The authorization data is the information that is saved or passed to provide proof of ownership + of an entity. For version 1 this area is always 20 bytes. +*/ + +#define TPM_AUTHDATA_SIZE 20 +typedef BYTE TPM_AUTHDATA[TPM_AUTHDATA_SIZE]; + +#define TPM_SECRET_SIZE 20 +typedef BYTE TPM_SECRET[TPM_SECRET_SIZE]; + +#if 0 /* kgold - define TPM_SECRET directly, so the size can be defined */ +typedef TPM_AUTHDATA TPM_SECRET; /* A secret plain text value used in the authorization process. */ +#endif + +typedef TPM_AUTHDATA TPM_ENCAUTH; /* A cipher text (encrypted) version of authorization data. The + encryption mechanism depends on the context. */ + +/* 5.7 TPM_KEY_HANDLE_LIST rev 87 + + TPM_KEY_HANDLE_LIST is a structure used to describe the handles of all keys currently loaded into + a TPM. +*/ + +#if 0 /* This is the version from the specification part 2 */ +typedef struct tdTPM_KEY_HANDLE_LIST { + uint16_t loaded; /* The number of keys currently loaded in the TPM. */ + [size_is(loaded)] TPM_KEY_HANDLE handle[]; /* An array of handles, one for each key currently + loaded in the TPM */ +} TPM_KEY_HANDLE_LIST; +#endif + +/* 5.11 TPM_CHANGEAUTH_VALIDATE rev 87 + + This structure provides an area that will stores the new authorization data and the challenger's + nonce. +*/ + +typedef struct tdTPM_CHANGEAUTH_VALIDATE { + TPM_SECRET newAuthSecret; /* This SHALL be the new authorization data for the target entity */ + TPM_NONCE n1; /* This SHOULD be a nonce, to enable the caller to verify that the + target TPM is on-line. */ +} TPM_CHANGEAUTH_VALIDATE; + + + +/* PCR */ + +/* NOTE: The TPM requires and the code assumes a multiple of CHAR_BIT (8). 48 registers (6 bytes) + may be a bad number, as it makes TPM_PCR_INFO and TPM_PCR_INFO_LONG indistinguishable in the + first two bytes. */ + +#if defined TPM_V11 +#define TPM_NUM_PCR 16 /* Use PC Client specification values */ +#endif + +#if defined TPM_V12 +#define TPM_NUM_PCR 24 /* Use PC Client specification values */ +#endif + +#if (CHAR_BIT != 8) +#error "CHAR_BIT must be 8" +#endif + +#if ((TPM_NUM_PCR % 8) != 0) +#error "TPM_NUM_PCR must be a multiple of 8" +#endif + +/* 8.1 TPM_PCR_SELECTION rev 110 + + This structure provides a standard method of specifying a list of PCR registers. +*/ + +typedef struct tdTPM_PCR_SELECTION { + uint16_t sizeOfSelect; /* The size in bytes of the pcrSelect structure */ + BYTE pcrSelect[TPM_NUM_PCR/CHAR_BIT]; /* This SHALL be a bit map that indicates if a PCR + is active or not */ +} TPM_PCR_SELECTION; + +/* 8.2 TPM_PCR_COMPOSITE rev 97 + + The composite structure provides the index and value of the PCR register to be used when creating + the value that SEALS an entity to the composite. +*/ + +typedef struct tdTPM_PCR_COMPOSITE { + TPM_PCR_SELECTION select; /* This SHALL be the indication of which PCR values are active */ +#if 0 + uint32_t valueSize; /* This SHALL be the size of the pcrValue field (not the number of + PCR's) */ + TPM_PCRVALUE *pcrValue; /* This SHALL be an array of TPM_PCRVALUE structures. The values + come in the order specified by the select parameter and are + concatenated into a single blob */ +#endif + TPM_SIZED_BUFFER pcrValue; +} TPM_PCR_COMPOSITE; + +/* 8.3 TPM_PCR_INFO rev 87 + + The TPM_PCR_INFO structure contains the information related to the wrapping of a key or the + sealing of data, to a set of PCRs. +*/ + +typedef struct tdTPM_PCR_INFO { + TPM_PCR_SELECTION pcrSelection; /* This SHALL be the selection of PCRs to which the + data or key is bound. */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing Sealed Data + or using a key that was wrapped to PCRs. NOTE: + This is passed in by the host, and used as + authorization to use the key */ + TPM_COMPOSITE_HASH digestAtCreation; /* This SHALL be the composite digest value of the + PCR values, at the time when the sealing is + performed. NOTE: This is generated at key + creation, but is just informative to the host, + not used for authorization */ +} TPM_PCR_INFO; + +/* 8.6 TPM_LOCALITY_SELECTION rev 87 + + When used with localityAtCreation only one bit is set and it corresponds to the locality of the + command creating the structure. + + When used with localityAtRelease the bits indicate which localities CAN perform the release. +*/ + +typedef BYTE TPM_LOCALITY_SELECTION; + +#define TPM_LOC_FOUR 0x10 /* Locality 4 */ +#define TPM_LOC_THREE 0x08 /* Locality 3 */ +#define TPM_LOC_TWO 0x04 /* Locality 2 */ +#define TPM_LOC_ONE 0x02 /* Locality 1 */ +#define TPM_LOC_ZERO 0x01 /* Locality 0. This is the same as the legacy interface. */ + +#define TPM_LOC_ALL 0x1f /* kgold - added all localities */ +#define TPM_LOC_MAX 4 /* kgold - maximum value for TPM_MODIFIER_INDICATOR */ + + +/* 8.4 TPM_PCR_INFO_LONG rev 109 + + The TPM_PCR_INFO structure contains the information related to the wrapping of a key or the + sealing of data, to a set of PCRs. + + The LONG version includes information necessary to properly define the configuration that creates + the blob using the PCR selection. +*/ + +typedef struct tdTPM_PCR_INFO_LONG { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_PCR_INFO_LONG */ +#endif + TPM_LOCALITY_SELECTION localityAtCreation; /* This SHALL be the locality modifier of the + function that creates the PCR info structure */ + TPM_LOCALITY_SELECTION localityAtRelease; /* This SHALL be the locality modifier required to + reveal Sealed Data or use a key that was wrapped + to PCRs */ + TPM_PCR_SELECTION creationPCRSelection; /* This SHALL be the selection of PCRs active when + the blob is created */ + TPM_PCR_SELECTION releasePCRSelection; /* This SHALL be the selection of PCRs to which the + data or key is bound. */ + TPM_COMPOSITE_HASH digestAtCreation; /* This SHALL be the composite digest value of the + PCR values, at the time when the sealing is + performed. */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing Sealed Data + or using a key that was wrapped to PCRs. */ +} TPM_PCR_INFO_LONG; + +/* 8.5 TPM_PCR_INFO_SHORT rev 87 + + This structure is for defining a digest at release when the only information that is necessary is + the release configuration. +*/ + +typedef struct tdTPM_PCR_INFO_SHORT { + TPM_PCR_SELECTION pcrSelection; /* This SHALL be the selection of PCRs that specifies the + digestAtRelease */ + TPM_LOCALITY_SELECTION localityAtRelease; /* This SHALL be the locality modifier required to + release the information. This value must not be + zero (0). */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing auth data */ +} TPM_PCR_INFO_SHORT; + +/* 8.8 TPM_PCR_ATTRIBUTES rev 107 + + These attributes are available on a per PCR basis. + + The TPM is not required to maintain this structure internally to the TPM. + + When a challenger evaluates a PCR an understanding of this structure is vital to the proper + understanding of the platform configuration. As this structure is static for all platforms of the + same type the structure does not need to be reported with each quote. +*/ + +typedef struct tdTPM_PCR_ATTRIBUTES { + TPM_BOOL pcrReset; /* A value of TRUE SHALL indicate that the PCR register can be reset + using the TPM_PCR_RESET command. */ + TPM_LOCALITY_SELECTION pcrExtendLocal; /* An indication of which localities can perform + extends on the PCR. */ + TPM_LOCALITY_SELECTION pcrResetLocal; /* An indication of which localities can reset the + PCR */ +} TPM_PCR_ATTRIBUTES; + +/* + 9. Storage Structures +*/ + +/* 9.1 TPM_STORED_DATA rev 87 + + The definition of this structure is necessary to ensure the enforcement of security properties. + + This structure is in use by the TPM_Seal and TPM_Unseal commands to identify the PCR index and + values that must be present to properly unseal the data. + + This structure only provides 1.1 data store and uses PCR_INFO + + 1. This structure is created during the TPM_Seal process. The confidential data is encrypted + using a nonmigratable key. When the TPM_Unseal decrypts this structure the TPM_Unseal uses the + public information in the structure to validate the current configuration and release the + decrypted data + + 2. When sealInfoSize is not 0 sealInfo MUST be TPM_PCR_INFO +*/ + +typedef struct tdTPM_STORED_DATA { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_SIZED_BUFFER sealInfo; +#if 0 + uint32_t sealInfoSize; /* Size of the sealInfo parameter */ + BYTE* sealInfo; /* This SHALL be a structure of type TPM_PCR_INFO or a 0 length + array if the data is not bound to PCRs. */ +#endif + TPM_SIZED_BUFFER encData; +#if 0 + uint32_t encDataSize; /* This SHALL be the size of the encData parameter */ + BYTE* encData; /* This shall be an encrypted TPM_SEALED_DATA structure containing + the confidential part of the data. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_seal_info; +} TPM_STORED_DATA; + + +/* 9.2 TPM_STORED_DATA12 rev 101 + + The definition of this structure is necessary to ensure the enforcement of security properties. + This structure is in use by the TPM_Seal and TPM_Unseal commands to identify the PCR index and + values that must be present to properly unseal the data. + + 1. This structure is created during the TPM_Seal process. The confidential data is encrypted + using a nonmigratable key. When the TPM_Unseal decrypts this structure the TPM_Unseal uses the + public information in the structure to validate the current configuration and release the + decrypted data. + + 2. If sealInfoSize is not 0 then sealInfo MUST be TPM_PCR_INFO_LONG +*/ + +typedef struct tdTPM_STORED_DATA12 { + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_STORED_DATA12 */ + TPM_ENTITY_TYPE et; /* The type of blob */ + TPM_SIZED_BUFFER sealInfo; +#if 0 + uint32_t sealInfoSize; /* Size of the sealInfo parameter */ + BYTE* sealInfo; /* This SHALL be a structure of type TPM_PCR_INFO_LONG or a 0 length + array if the data is not bound to PCRs. */ +#endif + TPM_SIZED_BUFFER encData; +#if 0 + uint32_t encDataSize; /* This SHALL be the size of the encData parameter */ + BYTE* encData; /* This shall be an encrypted TPM_SEALED_DATA structure containing + the confidential part of the data. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO_LONG *tpm_seal_info_long; +} TPM_STORED_DATA12; + +/* 9.3 TPM_SEALED_DATA rev 87 + + This structure contains confidential information related to sealed data, including the data + itself. + + 1. To tie the TPM_STORED_DATA structure to the TPM_SEALED_DATA structure this structure contains + a digest of the containing TPM_STORED_DATA structure. + + 2. The digest calculation does not include the encDataSize and encData parameters. +*/ + +typedef struct tdTPM_SEALED_DATA { + TPM_PAYLOAD_TYPE payload; /* This SHALL indicate the payload type of TPM_PT_SEAL */ + TPM_SECRET authData; /* This SHALL be the authorization data for this value */ + TPM_SECRET tpmProof; /* This SHALL be a copy of TPM_PERMANENT_FLAGS -> tpmProof */ + TPM_DIGEST storedDigest; /* This SHALL be a digest of the TPM_STORED_DATA structure, + excluding the fields TPM_STORED_DATA -> encDataSize and + TPM_STORED_DATA -> encData. */ + TPM_SIZED_BUFFER data; /* This SHALL be the data to be sealed */ +#if 0 + uint32_t dataSize; /* This SHALL be the size of the data parameter */ + BYTE* data; /* This SHALL be the data to be sealed */ +#endif +} TPM_SEALED_DATA; + + +/* 9.4 TPM_SYMMETRIC_KEY rev 87 + + This structure describes a symmetric key, used during the process "Collating a Request for a + Trusted Platform Module Identity". +*/ + +typedef struct tdTPM_SYMMETRIC_KEY { + TPM_ALGORITHM_ID algId; /* This SHALL be the algorithm identifier of the symmetric key. */ + TPM_ENC_SCHEME encScheme; /* This SHALL fully identify the manner in which the key will be + used for encryption operations. */ + uint16_t size; /* This SHALL be the size of the data parameter in bytes */ + BYTE* data; /* This SHALL be the symmetric key data */ + /* NOTE Cannot make this a TPM_SIZED_BUFFER because uint16_t */ +} TPM_SYMMETRIC_KEY; + +/* 9.5 TPM_BOUND_DATA rev 87 + + This structure is defined because it is used by a TPM_UnBind command in a consistency check. + + The intent of TCG is to promote "best practice" heuristics for the use of keys: a signing key + shouldn't be used for storage, and so on. These heuristics are used because of the potential + threats that arise when the same key is used in different ways. The heuristics minimize the + number of ways in which a given key can be used. + + One such heuristic is that a key of type TPM_KEY_BIND, and no other type of key, should always be + used to create the blob that is unwrapped by TPM_UnBind. Binding is not a TPM function, so the + only choice is to perform a check for the correct payload type when a blob is unwrapped by a key + of type TPM_KEY_BIND. This requires the blob to have internal structure. + + Even though payloadData has variable size, TPM_BOUND_DATA deliberately does not include the size + of payloadData. This is to maximise the size of payloadData that can be encrypted when + TPM_BOUND_DATA is encrypted in a single block. When using TPM-UnBind to obtain payloadData, the + size of payloadData is deduced as a natural result of the (RSA) decryption process. + + 1. This structure MUST be used for creating data when (wrapping with a key of type TPM_KEY_BIND) + or (wrapping using the encryption algorithm TPM_ES_RSAESOAEP_SHA1_MGF1). If it is not, the + TPM_UnBind command will fail. +*/ + +typedef struct tdTPM_BOUND_DATA { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_PAYLOAD_TYPE payload; /* This SHALL be the value TPM_PT_BIND */ + uint32_t payloadDataSize; /* NOTE: added, not part of serialization */ + BYTE *payloadData; /* The bound data */ +} TPM_BOUND_DATA; + +/* + 10. TPM_KEY Complex +*/ + +/* 10.1.1 TPM_RSA_KEY_PARMS rev 87 + + This structure describes the parameters of an RSA key. +*/ + +/* TPM_RSA_KEY_LENGTH_MAX restricts the maximum size of an RSA key. It has two uses: + - bounds the size of the TPM state + - protects against a denial of service attack where the attacker creates a very large key +*/ + +#ifdef TPM_RSA_KEY_LENGTH_MAX /* if the builder defines a value */ +#if ((TPM_RSA_KEY_LENGTH_MAX % 16) != 0) +#error "TPM_RSA_KEY_LENGTH_MAX must be a multiple of 16" +#endif +#if (TPM_RSA_KEY_LENGTH_MAX < 2048) +#error "TPM_RSA_KEY_LENGTH_MAX must be at least 2048" +#endif +#endif /* TPM_RSA_KEY_LENGTH_MAX */ + +#ifndef TPM_RSA_KEY_LENGTH_MAX /* default if the builder does not define a value */ +#define TPM_RSA_KEY_LENGTH_MAX 2048 +#endif + +typedef struct tdTPM_RSA_KEY_PARMS { + uint32_t keyLength; /* This specifies the size of the RSA key in bits */ + uint32_t numPrimes; /* This specifies the number of prime factors used by this RSA key. */ +#if 0 + uint32_t exponentSize; /* This SHALL be the size of the exponent. If the key is using the + default exponent then the exponentSize MUST be 0. */ + BYTE *exponent; /* The public exponent of this key */ +#endif + TPM_SIZED_BUFFER exponent; /* The public exponent of this key */ + +} TPM_RSA_KEY_PARMS; + + +/* 10.1 TPM_KEY_PARMS rev 87 + + This provides a standard mechanism to define the parameters used to generate a key pair, and to + store the parts of a key shared between the public and private key parts. +*/ + +typedef struct tdTPM_KEY_PARMS { + TPM_ALGORITHM_ID algorithmID; /* This SHALL be the key algorithm in use */ + TPM_ENC_SCHEME encScheme; /* This SHALL be the encryption scheme that the key uses to encrypt + information */ + TPM_SIG_SCHEME sigScheme; /* This SHALL be the signature scheme that the key uses to perform + digital signatures */ +#if 0 + uint32_t parmSize; /* This SHALL be the size of the parms field in bytes */ + BYTE* parms; /* This SHALL be the parameter information dependent upon the key + algorithm. */ +#endif + TPM_SIZED_BUFFER parms; /* This SHALL be the parameter information dependent upon the key + algorithm. */ + /* NOTE: kgold - Added this structure. It acts as a cache of the result of parms and parmSize + deserialization when non-NULL. */ + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; +} TPM_KEY_PARMS; + +/* 10.1.2 TPM_SYMMETRIC_KEY_PARMS rev 87 + + This structure describes the parameters for symmetric algorithms +*/ + +typedef struct tdTPM_SYMMETRIC_KEY_PARMS { + uint32_t keyLength; /* This SHALL indicate the length of the key in bits */ + uint32_t blockSize; /* This SHALL indicate the block size of the algorithm*/ + uint32_t ivSize; /* This SHALL indicate the size of the IV */ + BYTE *IV; /* The initialization vector */ +} TPM_SYMMETRIC_KEY_PARMS; + +#if 0 +/* 10.4 TPM_STORE_PUBKEY rev 99 + + This structure can be used in conjunction with a corresponding TPM_KEY_PARMS to construct a + public key which can be unambiguously used. +*/ + +typedef struct tdTPM_STORE_PUBKEY { + uint32_t keyLength; /* This SHALL be the length of the key field. */ + BYTE *key; /* This SHALL be a structure interpreted according to the algorithm Id in + the corresponding TPM_KEY_PARMS structure. */ +} TPM_STORE_PUBKEY; +#endif + +/* 10.7 TPM_STORE_PRIVKEY rev 87 + + This structure can be used in conjunction with a corresponding TPM_PUBKEY to construct a private + key which can be unambiguously used. +*/ + +#if 0 +typedef struct tdTPM_STORE_PRIVKEY { + uint32_t keyLength; /* This SHALL be the length of the key field. */ + BYTE* key; /* This SHALL be a structure interpreted according to the algorithm Id in + the corresponding TPM_KEY structure. */ +} TPM_STORE_PRIVKEY; +#endif + +/* NOTE: Hard coded for RSA keys. This will change if other algorithms are supported */ + +typedef struct tdTPM_STORE_PRIVKEY { + TPM_SIZED_BUFFER d_key; /* private key */ + TPM_SIZED_BUFFER p_key; /* private prime factor */ + TPM_SIZED_BUFFER q_key; /* private prime factor */ +} TPM_STORE_PRIVKEY; + +/* 10.6 TPM_STORE_ASYMKEY rev 87 + + The TPM_STORE_ASYMKEY structure provides the area to identify the confidential information + related to a key. This will include the private key factors for an asymmetric key. + + The structure is designed so that encryption of a TPM_STORE_ASYMKEY structure containing a 2048 + bit RSA key can be done in one operation if the encrypting key is 2048 bits. + + Using typical RSA notation the structure would include P, and when loading the key include the + unencrypted P*Q which would be used to recover the Q value. + + To accommodate the future use of multiple prime RSA keys the specification of additional prime + factors is an optional capability. + + This structure provides the basis of defining the protection of the private key. Changes in this + structure MUST be reflected in the TPM_MIGRATE_ASYMKEY structure (section 10.8). +*/ + +typedef struct tdTPM_STORE_ASYMKEY { + TPM_PAYLOAD_TYPE payload; /* This SHALL set to TPM_PT_ASYM to indicate an asymmetric + key. If used in TPM_CMK_ConvertMigration the value SHALL + be TPM_PT_MIGRATE_EXTERNAL. If used in TPM_CMK_CreateKey + the value SHALL be TPM_PT_MIGRATE_RESTRICTED */ + TPM_SECRET usageAuth; /* This SHALL be the authorization data necessary to + authorize the use of this value */ + TPM_SECRET migrationAuth; /* This SHALL be the migration authorization data for a + migratable key, or the TPM secret value tpmProof for a + non-migratable key created by the TPM. + + If the TPM sets this parameter to the value tpmProof, + then the TPM_KEY.keyFlags.migratable of the corresponding + TPM_KEY structure MUST be set to 0. + + If this parameter is set to the migration authorization + data for the key in parameter PrivKey, then the + TPM_KEY.keyFlags.migratable of the corresponding TPM_KEY + structure SHOULD be set to 1. */ + TPM_DIGEST pubDataDigest; /* This SHALL be the digest of the corresponding TPM_KEY + structure, excluding the fields TPM_KEY.encSize and + TPM_KEY.encData. + + When TPM_KEY -> pcrInfoSize is 0 then the digest + calculation has no input from the pcrInfo field. The + pcrInfoSize field MUST always be part of the digest + calculation. + */ + TPM_STORE_PRIVKEY privKey; /* This SHALL be the private key data. The privKey can be a + variable length which allows for differences in the key + format. The maximum size of the area would be 151 + bytes. */ +} TPM_STORE_ASYMKEY; + +/* 10.8 TPM_MIGRATE_ASYMKEY rev 87 + + The TPM_MIGRATE_ASYMKEY structure provides the area to identify the private key factors of a + asymmetric key while the key is migrating between TPM's. + + This structure provides the basis of defining the protection of the private key. + + k1k2 - 132 privkey.key (128 + 4) + k1 - 20, OAEP seed + k2 - 112, partPrivKey + TPM_STORE_PRIVKEY 4 partPrivKey.keyLength + 108 partPrivKey.key (128 - 20) +*/ + +typedef struct tdTPM_MIGRATE_ASYMKEY { + TPM_PAYLOAD_TYPE payload; /* This SHALL set to TPM_PT_MIGRATE or TPM_PT_CMK_MIGRATE to + indicate an migrating asymmetric key or TPM_PT_MAINT to indicate + a maintenance key. */ + TPM_SECRET usageAuth; /* This SHALL be a copy of the usageAuth from the TPM_STORE_ASYMKEY + structure. */ + TPM_DIGEST pubDataDigest; /* This SHALL be a copy of the pubDataDigest from the + TPM_STORE_ASYMKEY structure. */ +#if 0 + uint32_t partPrivKeyLen; /* This SHALL be the size of the partPrivKey field */ + BYTE *partPrivKey; /* This SHALL be the k2 area as described in TPM_CreateMigrationBlob + */ +#endif + TPM_SIZED_BUFFER partPrivKey; +} TPM_MIGRATE_ASYMKEY; + +/* 10.2 TPM_KEY rev 87 + + The TPM_KEY structure provides a mechanism to transport the entire asymmetric key pair. The + private portion of the key is always encrypted. + + The reason for using a size and pointer for the PCR info structure is save space when the key is + not bound to a PCR. The only time the information for the PCR is kept with the key is when the + key needs PCR info. + + The 1.2 version has a change in the PCRInfo area. For 1.2 the structure uses the + TPM_PCR_INFO_LONG structure to properly define the PCR registers in use. +*/ + +typedef struct tdTPM_KEY { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the TPM key usage that determines the operations + permitted with this key */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be the indication of migration, redirection etc.*/ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL Indicate the conditions where it is required + that authorization be presented.*/ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding the algorithm for + this key*/ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the length of the pcrInfo parameter. If the key is + not bound to a PCR this value SHOULD be 0.*/ + BYTE* PCRInfo; /* This SHALL be a structure of type TPM_PCR_INFO, or an empty array + if the key is not bound to PCRs.*/ + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public portion of the key */ + uint32_t encDataSize; /* This SHALL be the size of the encData parameter. */ + BYTE* encData; /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure or + TPM_MIGRATE_ASYMKEY structure */ +#endif + TPM_SIZED_BUFFER pcrInfo; + TPM_SIZED_BUFFER pubKey; + TPM_SIZED_BUFFER encData; + /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure or TPM_MIGRATE_ASYMKEY structure */ + /* NOTE: kgold - Added these structures, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_pcr_info; /* for TPM_KEY */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long; /* for TPM_KEY12 */ + /* NOTE: kgold - Added these structures. They act as a cache of the result of encData + decryption when non-NULL. In the case of internal keys (e.g. SRK) there is no encData, so + these structures are always non-NULL. */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey; +} TPM_KEY; + +/* 10.3 TPM_KEY12 rev 87 + + This provides the same functionality as TPM_KEY but uses the new PCR_INFO_LONG structures and the + new structure tagging. In all other aspects this is the same structure. +*/ + +/* NOTE: The TPM_KEY12 structure is never instantiated. It is just needed for the cast of TPM_KEY + to get the TPM_KEY12->tag member. */ + +typedef struct tdTPM_KEY12 { + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_KEY12 */ + uint16_t fill; /* MUST be 0x0000 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the TPM key usage that determines the operations + permitted with this key */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be the indication of migration, redirection etc. */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL Indicate the conditions where it is required + that authorization be presented. */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding the algorithm for + this key */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the length of the pcrInfo parameter. If the key is + not bound to a PCR this value SHOULD be 0. */ + BYTE* PCRInfo; /* This SHALL be a structure of type TPM_PCR_INFO_LONG, or an empty + array if the key is not bound to PCRs. */ + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public portion of the key */ + uint32_t encDataSize; /* This SHALL be the size of the encData parameter. */ + BYTE* encData; /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure + TPM_MIGRATE_ASYMKEY structure */ +#endif + TPM_SIZED_BUFFER pcrInfo; + TPM_SIZED_BUFFER pubKey; + TPM_SIZED_BUFFER encData; +} TPM_KEY12; + + +/* 10.5 TPM_PUBKEY rev 99 + + The TPM_PUBKEY structure contains the public portion of an asymmetric key pair. It contains all + the information necessary for its unambiguous usage. It is possible to construct this structure + from a TPM_KEY, using the algorithmParms and pubKey fields. + + The pubKey member of this structure shall contain the public key for a specific algorithm. +*/ + +typedef struct tdTPM_PUBKEY { + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding this key */ +#if 0 + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public key information */ +#endif + TPM_SIZED_BUFFER pubKey; +} TPM_PUBKEY; + +/* 5.b. The TPM must support a minimum of 2 key slots. */ + +#ifdef TPM_KEY_HANDLES +#if (TPM_KEY_HANDLES < 2) +#error "TPM_KEY_HANDLES minimum is 2" +#endif +#endif + +/* Set the default to 3 so that there can be one owner evict key */ + +#ifndef TPM_KEY_HANDLES +#define TPM_KEY_HANDLES 3 /* entries in global TPM_KEY_HANDLE_ENTRY array */ +#endif + +/* TPM_GetCapability uses a uint_16 for the number of key slots */ + +#if (TPM_KEY_HANDLES > 0xffff) +#error "TPM_KEY_HANDLES must be less than 0x10000" +#endif + +/* The TPM does not have to support any minimum number of owner evict keys. Adjust this value to + match the amount of NV space available. An owner evict key consumes about 512 bytes. + + A value greater than (TPM_KEY_HANDLES - 2) is useless, as the TPM reserves 2 key slots for + non-owner evict keys to avoid blocking. +*/ + +#ifndef TPM_OWNER_EVICT_KEY_HANDLES +#define TPM_OWNER_EVICT_KEY_HANDLES 1 +#endif + +#if (TPM_OWNER_EVICT_KEY_HANDLES > (TPM_KEY_HANDLES - 2)) +#error "TPM_OWNER_EVICT_KEY_HANDLES too large for TPM_KEY_HANDLES" +#endif + +/* This is the version used by the TPM implementation. It is part of the global TPM state */ + +/* kgold: Added TPM_KEY member. There needs to be a mapping between a key handle + and the pointer to TPM_KEY objects, and this seems to be the right place for it. */ + +typedef struct tdTPM_KEY_HANDLE_ENTRY { + TPM_KEY_HANDLE handle; /* Handles for a key currently loaded in the TPM */ + TPM_KEY *key; /* Pointer to the key object */ + TPM_BOOL parentPCRStatus; /* TRUE if parent of this key uses PCR's */ + TPM_KEY_CONTROL keyControl; /* Attributes that can control various aspects of key usage and + manipulation. */ +} TPM_KEY_HANDLE_ENTRY; + +/* 5.12 TPM_MIGRATIONKEYAUTH rev 87 + + This structure provides the proof that the associated public key has TPM Owner authorization to + be a migration key. +*/ + +typedef struct tdTPM_MIGRATIONKEYAUTH { + TPM_PUBKEY migrationKey; /* This SHALL be the public key of the migration facility */ + TPM_MIGRATE_SCHEME migrationScheme; /* This shall be the type of migration operation.*/ + TPM_DIGEST digest; /* This SHALL be the digest value of the concatenation of + migration key, migration scheme and tpmProof */ +} TPM_MIGRATIONKEYAUTH; + +/* 5.13 TPM_COUNTER_VALUE rev 87 + + This structure returns the counter value. For interoperability, the value size should be 4 bytes. +*/ + +#define TPM_COUNTER_LABEL_SIZE 4 +#define TPM_COUNT_ID_NULL 0xffffffff /* unused value TPM_CAP_PROP_ACTIVE_COUNTER expects this + value if no counter is active */ +#define TPM_COUNT_ID_ILLEGAL 0xfffffffe /* after releasing an active counter */ + +typedef struct tdTPM_COUNTER_VALUE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_COUNTER_VALUE */ +#endif + BYTE label[TPM_COUNTER_LABEL_SIZE]; /* The label for the counter */ + TPM_ACTUAL_COUNT counter; /* The 32-bit counter value. */ + /* NOTE: Added. TPMWG email says the specification structure is the public part, but these are + vendor specific private members. */ + TPM_SECRET authData; /* Authorization secret for counter */ + TPM_BOOL valid; + TPM_DIGEST digest; /* for OSAP comparison */ +} TPM_COUNTER_VALUE; + +/* 5.14 TPM_SIGN_INFO Structure rev 102 + + This is an addition in 1.2 and is the structure signed for certain commands (e.g., + TPM_ReleaseTransportSigned). Some commands have a structure specific to that command (e.g., + TPM_Quote uses TPM_QUOTE_INFO) and do not use TPM_SIGN_INFO. + + TPM_Sign uses this structure when the signature scheme is TPM_SS_RSASSAPKCS1v15_INFO. +*/ + +#define TPM_SIGN_INFO_FIXED_SIZE 4 + +typedef struct tdTPM_SIGN_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_SIGNINFO */ +#endif + BYTE fixed[TPM_SIGN_INFO_FIXED_SIZE]; /* The ASCII text that identifies what function was + performing the signing operation*/ + TPM_NONCE replay; /* Nonce provided by caller to prevent replay attacks */ +#if 0 + uint32_t dataLen; /* The length of the data area */ + BYTE* data; /* The data that is being signed */ +#endif + TPM_SIZED_BUFFER data; /* The data that is being signed */ +} TPM_SIGN_INFO; + +/* 5.15 TPM_MSA_COMPOSITE Structure rev 87 + + TPM_MSA_COMPOSITE contains an arbitrary number of digests of public keys belonging to Migration + Authorities. An instance of TPM_MSA_COMPOSITE is incorporated into the migrationAuth value of a + certified-migration-key (CMK), and any of the Migration Authorities specified in that instance is + able to approve the migration of that certified-migration-key. + + TPMs MUST support TPM_MSA_COMPOSITE structures with MSAlist of four (4) or less, and MAY support + larger values of MSAlist. +*/ + +typedef struct tdTPM_MSA_COMPOSITE { + uint32_t MSAlist; /* The number of migAuthDigests. MSAlist MUST be one (1) or + greater. */ + TPM_DIGEST *migAuthDigest; /* An arbitrary number of digests of public keys belonging + to Migration Authorities. */ +} TPM_MSA_COMPOSITE; + +/* 5.16 TPM_CMK_AUTH + + The signed digest of TPM_CMK_AUTH is a ticket to prove that the entity with public key + "migrationAuthority" has approved the public key "destination Key" as a migration destination for + the key with public key "sourceKey". + + Normally the digest of TPM_CMK_AUTH is signed by the private key corresponding to + "migrationAuthority". + + To reduce data size, TPM_CMK_AUTH contains just the digests of "migrationAuthority", + "destinationKey" and "sourceKey". +*/ + +typedef struct tdTPM_CMK_AUTH { + TPM_DIGEST migrationAuthorityDigest; /* The digest of the public key of a Migration + Authority */ + TPM_DIGEST destinationKeyDigest; /* The digest of a TPM_PUBKEY structure that is an + approved destination key for the private key + associated with "sourceKey"*/ + TPM_DIGEST sourceKeyDigest; /* The digest of a TPM_PUBKEY structure whose + corresponding private key is approved by the + Migration Authority to be migrated as a child to + the destinationKey. */ +} TPM_CMK_AUTH; + +/* 5.18 TPM_SELECT_SIZE rev 87 + + This structure provides the indication for the version and sizeOfSelect structure in GetCapability +*/ + +typedef struct tdTPM_SELECT_SIZE { + BYTE major; /* This SHALL indicate the major version of the TPM. This MUST be 0x01 */ + BYTE minor; /* This SHALL indicate the minor version of the TPM. This MAY be 0x01 or + 0x02 */ + uint16_t reqSize; /* This SHALL indicate the value for a sizeOfSelect field in the + TPM_SELECTION structure */ +} TPM_SELECT_SIZE; + +/* 5.19 TPM_CMK_MIGAUTH rev 89 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_MIGAUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_MIGAUTH */ +#endif + TPM_DIGEST msaDigest; /* The digest of a TPM_MSA_COMPOSITE structure containing the + migration authority public key and parameters. */ + TPM_DIGEST pubKeyDigest; /* The hash of the associated public key */ +} TPM_CMK_MIGAUTH; + +/* 5.20 TPM_CMK_SIGTICKET rev 87 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_SIGTICKET { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_SIGTICKET */ +#endif + TPM_DIGEST verKeyDigest; /* The hash of a TPM_PUBKEY structure containing the public key and + parameters of the key that can verify the ticket */ + TPM_DIGEST signedData; /* The ticket data */ +} TPM_CMK_SIGTICKET; + +/* 5.21 TPM_CMK_MA_APPROVAL rev 87 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_MA_APPROVAL { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_MA_APPROVAL */ +#endif + TPM_DIGEST migrationAuthorityDigest; /* The hash of a TPM_MSA_COMPOSITE structure + containing the hash of one or more migration + authority public keys and parameters. */ +} TPM_CMK_MA_APPROVAL; + +/* 20.2 Delegate Definitions rev 101 + + The delegations are in a 64-bit field. Each bit describes a capability that the TPM Owner can + delegate to a trusted process by setting that bit. Each delegation bit setting is independent of + any other delegation bit setting in a row. + + If a TPM command is not listed in the following table, then the TPM Owner cannot delegate that + capability to a trusted process. For the TPM commands that are listed in the following table, if + the bit associated with a TPM command is set to zero in the row of the table that identifies a + trusted process, then that process has not been delegated to use that TPM command. + + The minimum granularity for delegation is at the ordinal level. It is not possible to delegate an + option of an ordinal. This implies that if the options present a difficulty and there is a need + to separate the delegations then there needs to be a split into two separate ordinals. +*/ + +#define TPM_DEL_OWNER_BITS 0x00000001 +#define TPM_DEL_KEY_BITS 0x00000002 + +typedef struct tdTPM_DELEGATIONS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATIONS */ +#endif + uint32_t delegateType; /* Owner or key */ + uint32_t per1; /* The first block of permissions */ + uint32_t per2; /* The second block of permissions */ +} TPM_DELEGATIONS; + +/* 20.4 TPM_FAMILY_LABEL rev 85 + + Used in the family table to hold a one-byte numeric value (sequence number) that software can map + to a string of bytes that can be displayed or used by applications. + + This is not sensitive data. +*/ + +#if 0 +typedef struct tdTPM_FAMILY_LABEL { + BYTE label; /* A sequence number that software can map to a string of bytes that can be + displayed or used by the applications. This MUST not contain sensitive + information. */ +} TPM_FAMILY_LABEL; +#endif + +typedef BYTE TPM_FAMILY_LABEL; /* NOTE: No need for a structure here */ + +/* 20.5 TPM_FAMILY_TABLE_ENTRY rev 101 + + The family table entry is an individual row in the family table. There are no sensitive values in + a family table entry. + + Each family table entry contains values to facilitate table management: the familyID sequence + number value that associates a family table row with one or more delegate table rows, a + verification sequence number value that identifies when rows in the delegate table were last + verified, and BYTE family label value that software can map to an ASCII text description of the + entity using the family table entry +*/ + +typedef struct tdTPM_FAMILY_TABLE_ENTRY { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_FAMILY_TABLE_ENTRY */ +#endif + TPM_FAMILY_LABEL familyLabel; /* A sequence number that software can map to a string of + bytes that can be displayed of used by the applications. + This MUST not contain sensitive information. */ + TPM_FAMILY_ID familyID; /* The family ID in use to tie values together. This is not + a sensitive value. */ + TPM_FAMILY_VERIFICATION verificationCount; /* The value inserted into delegation rows to + indicate that they are the current generation of + rows. Used to identify when a row in the delegate + table was last verified. This is not a sensitive + value. */ + TPM_FAMILY_FLAGS flags; /* See section on TPM_FAMILY_FLAGS. */ + /* NOTE Added */ + TPM_BOOL valid; +} TPM_FAMILY_TABLE_ENTRY; + +/* 20.6 TPM_FAMILY_TABLE rev 87 + + The family table is stored in a TPM shielded location. There are no confidential values in the + family table. The family table contains a minimum of 8 rows. +*/ + +#ifdef TPM_NUM_FAMILY_TABLE_ENTRY_MIN +#if (TPM_NUM_FAMILY_TABLE_ENTRY_MIN < 8) +#error "TPM_NUM_FAMILY_TABLE_ENTRY_MIN minimum is 8" +#endif +#endif + +#ifndef TPM_NUM_FAMILY_TABLE_ENTRY_MIN +#define TPM_NUM_FAMILY_TABLE_ENTRY_MIN 8 +#endif + +typedef struct tdTPM_FAMILY_TABLE { + TPM_FAMILY_TABLE_ENTRY famTableRow[TPM_NUM_FAMILY_TABLE_ENTRY_MIN]; +} TPM_FAMILY_TABLE; + +/* 20.7 TPM_DELEGATE_LABEL rev 87 + + Used in both the delegate table and the family table to hold a string of bytes that can be + displayed or used by applications. This is not sensitive data. +*/ + +#if 0 +typedef struct tdTPM_DELEGATE_LABEL { + BYTE label; /* A byte that can be displayed or used by the applications. This MUST not + contain sensitive information. */ +} TPM_DELEGATE_LABEL; +#endif + +typedef BYTE TPM_DELEGATE_LABEL; /* NOTE: No need for structure */ + +/* 20.8 TPM_DELEGATE_PUBLIC rev 101 + + The information of a delegate row that is public and does not have any sensitive information. + + PCR_INFO_SHORT is appropriate here as the command to create this is done using owner + authorization, hence the owner authorized the command and the delegation. There is no need to + validate what configuration was controlling the platform during the blob creation. +*/ + +typedef struct tdTPM_DELEGATE_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATE_PUBLIC */ +#endif + TPM_DELEGATE_LABEL rowLabel; /* This SHALL be the label for the row. It + MUST not contain any sensitive information. */ + TPM_PCR_INFO_SHORT pcrInfo; /* This SHALL be the designation of the process that can use + the permission. This is a not sensitive + value. PCR_SELECTION may be NULL. + + If selected the pcrInfo MUST be checked on each use of + the delegation. Use of the delegation is where the + delegation is passed as an authorization handle. */ + TPM_DELEGATIONS permissions; /* This SHALL be the permissions that are allowed to the + indicated process. This is not a sensitive value. */ + TPM_FAMILY_ID familyID; /* This SHALL be the family ID that identifies which family + the row belongs to. This is not a sensitive value. */ + TPM_FAMILY_VERIFICATION verificationCount; /* A copy of verificationCount from the associated + family table. This is not a sensitive value. */ +} TPM_DELEGATE_PUBLIC; + + +/* 20.9 TPM_DELEGATE_TABLE_ROW rev 101 + + A row of the delegate table. +*/ + +typedef struct tdTPM_DELEGATE_TABLE_ROW { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATE_TABLE_ROW */ +#endif + TPM_DELEGATE_PUBLIC pub; /* This SHALL be the public information for a table row. */ + TPM_SECRET authValue; /* This SHALL be the authorization value that can use the + permissions. This is a sensitive value. */ + /* NOTE Added */ + TPM_BOOL valid; +} TPM_DELEGATE_TABLE_ROW; + +/* 20.10 TPM_DELEGATE_TABLE rev 87 + + This is the delegate table. The table contains a minimum of 2 rows. + + This will be an entry in the TPM_PERMANENT_DATA structure. +*/ + +#ifdef TPM_NUM_DELEGATE_TABLE_ENTRY_MIN +#if (TPM_NUM_DELEGATE_TABLE_ENTRY_MIN < 2) +#error "TPM_NUM_DELEGATE_TABLE_ENTRY_MIN minimum is 2" +#endif +#endif + +#ifndef TPM_NUM_DELEGATE_TABLE_ENTRY_MIN +#define TPM_NUM_DELEGATE_TABLE_ENTRY_MIN 2 +#endif + + +typedef struct tdTPM_DELEGATE_TABLE { + TPM_DELEGATE_TABLE_ROW delRow[TPM_NUM_DELEGATE_TABLE_ENTRY_MIN]; /* The array of delegations */ +} TPM_DELEGATE_TABLE; + +/* 20.11 TPM_DELEGATE_SENSITIVE rev 115 + + The TPM_DELEGATE_SENSITIVE structure is the area of a delegate blob that contains sensitive + information. + + This structure is normative for loading unencrypted blobs before there is an owner. It is + informative for TPM_CreateOwnerDelegation and TPM_LoadOwnerDelegation after there is an owner and + encrypted blobs are used, since the structure is under complete control of the TPM. +*/ + +typedef struct tdTPM_DELEGATE_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELEGATE_SENSITIVE */ +#endif + TPM_SECRET authValue; /* AuthData value */ +} TPM_DELEGATE_SENSITIVE; + +/* 20.12 TPM_DELEGATE_OWNER_BLOB rev 87 + + This data structure contains all the information necessary to externally store a set of owner + delegation rights that can subsequently be loaded or used by this TPM. + + The encryption mechanism for the sensitive area is a TPM choice. The TPM may use asymmetric + encryption and the SRK for the key. The TPM may use symmetric encryption and a secret key known + only to the TPM. +*/ + +typedef struct tdTPM_DELEGATE_OWNER_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELG_OWNER_BLOB */ +#endif + TPM_DELEGATE_PUBLIC pub; /* The public information for this blob */ + TPM_DIGEST integrityDigest; /* The HMAC to guarantee the integrity of the entire structure */ + TPM_SIZED_BUFFER additionalArea; /* An area that the TPM can add to the blob which MUST NOT + contain any sensitive information. This would include any + IV material for symmetric encryption */ + TPM_SIZED_BUFFER sensitiveArea; /* The area that contains the encrypted + TPM_DELEGATE_SENSITIVE */ +} TPM_DELEGATE_OWNER_BLOB; + +/* 20.13 TPM_DELEGATE_KEY_BLOB rev 87 + + A structure identical to TPM_DELEGATE_OWNER_BLOB but which stores delegation information for user + keys. As compared to TPM_DELEGATE_OWNER_BLOB, it adds a hash of the corresponding public key + value to the public information. +*/ + +typedef struct tdTPM_DELEGATE_KEY_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELG_KEY_BLOB */ +#endif + TPM_DELEGATE_PUBLIC pub; /* The public information for this blob */ + TPM_DIGEST integrityDigest; /* The HMAC to guarantee the integrity of the entire + structure */ + TPM_DIGEST pubKeyDigest; /* The digest, that uniquely identifies the key for which + this usage delegation applies. */ + TPM_SIZED_BUFFER additionalArea; /* An area that the TPM can add to the blob which MUST NOT + contain any sensitive information. This would include any + IV material for symmetric encryption */ + TPM_SIZED_BUFFER sensitiveArea; /* The area that contains the encrypted + TPM_DELEGATE_SENSITIVE */ +} TPM_DELEGATE_KEY_BLOB; + +/* 15.1 TPM_CURRENT_TICKS rev 110 + + This structure holds the current number of time ticks in the TPM. The value is the number of time + ticks from the start of the current session. Session start is a variable function that is + platform dependent. Some platforms may have batteries or other power sources and keep the TPM + clock session across TPM initialization sessions. + + The <tickRate> element of the TPM_CURRENT_TICKS structure provides the number of microseconds per + tick. The platform manufacturer must satisfy input clock requirements set by the TPM vendor to + ensure the accuracy of the tickRate. + + No external entity may ever set the current number of time ticks held in TPM_CURRENT_TICKS. This + value is always reset to 0 when a new clock session starts and increments under control of the + TPM. + + Maintaining the relationship between the number of ticks counted by the TPM and some real world + clock is a task for external software. +*/ + +/* This is not a true UINT64, but a special structure to hold currentTicks */ + +typedef struct tdTPM_UINT64 { + uint32_t sec; + uint32_t usec; +} TPM_UINT64; + +typedef struct tdTPM_CURRENT_TICKS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_CURRENT_TICKS */ +#endif + TPM_UINT64 currentTicks; /* The number of ticks since the start of this tick session */ + /* upper is seconds, lower is useconds */ + uint16_t tickRate; /* The number of microseconds per tick. The maximum resolution of + the TPM tick counter is thus 1 microsecond. The minimum + resolution SHOULD be 1 millisecond. */ + TPM_NONCE tickNonce; /* TPM_NONCE tickNonce The nonce created by the TPM when resetting + the currentTicks to 0. This indicates the beginning of a time + session. This value MUST be valid before the first use of + TPM_CURRENT_TICKS. The value can be set at TPM_Startup or just + prior to first use. */ + /* NOTE Added */ + TPM_UINT64 initialTime; /* Time from TPM_GetTimeOfDay() */ +} TPM_CURRENT_TICKS; + +/* + 13. Transport Structures +*/ + +/* 13.1 TPM _TRANSPORT_PUBLIC rev 87 + + The public information relative to a transport session +*/ + +typedef struct tdTPM_TRANSPORT_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_PUBLIC */ +#endif + TPM_TRANSPORT_ATTRIBUTES transAttributes; /* The attributes of this session */ + TPM_ALGORITHM_ID algId; /* This SHALL be the algorithm identifier of the + symmetric key. */ + TPM_ENC_SCHEME encScheme; /* This SHALL fully identify the manner in which the + key will be used for encryption operations. */ +} TPM_TRANSPORT_PUBLIC; + +/* 13.2 TPM_TRANSPORT_INTERNAL rev 88 + + The internal information regarding transport session +*/ + +/* 7.6 TPM_STANY_DATA */ + +#ifdef TPM_MIN_TRANS_SESSIONS +#if (TPM_MIN_TRANS_SESSIONS < 3) +#error "TPM_MIN_TRANS_SESSIONS minimum is 3" +#endif +#endif + +#ifndef TPM_MIN_TRANS_SESSIONS +#define TPM_MIN_TRANS_SESSIONS 3 +#endif + +typedef struct tdTPM_TRANSPORT_INTERNAL { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_INTERNAL */ +#endif + TPM_AUTHDATA authData; /* The shared secret for this session */ + TPM_TRANSPORT_PUBLIC transPublic; /* The public information of this session */ + TPM_TRANSHANDLE transHandle; /* The handle for this session */ + TPM_NONCE transNonceEven; /* The even nonce for the rolling protocol */ + TPM_DIGEST transDigest; /* The log of transport events */ + /* added kgold */ + TPM_BOOL valid; /* entry is valid */ +} TPM_TRANSPORT_INTERNAL; + +/* 13.3 TPM_TRANSPORT_LOG_IN rev 87 + + The logging of transport commands occurs in two steps, before execution with the input + parameters and after execution with the output parameters. + + This structure is in use for input log calculations. +*/ + +typedef struct tdTPM_TRANSPORT_LOG_IN { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_LOG_IN */ +#endif + TPM_DIGEST parameters; /* The actual parameters contained in the digest are subject to the + rules of the command using this structure. To find the exact + calculation refer to the actions in the command using this + structure. */ + TPM_DIGEST pubKeyHash; /* The hash of any keys in the transport command */ +} TPM_TRANSPORT_LOG_IN; + +/* 13.4 TPM_TRANSPORT_LOG_OUT rev 88 + + The logging of transport commands occurs in two steps, before execution with the input parameters + and after execution with the output parameters. + + This structure is in use for output log calculations. + + This structure is in use for the INPUT logging during releaseTransport. +*/ + +typedef struct tdTPM_TRANSPORT_LOG_OUT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_LOG_OUT */ +#endif + TPM_CURRENT_TICKS currentTicks; /* The current tick count. This SHALL be the value of the + current TPM tick counter. */ + TPM_DIGEST parameters; /* The actual parameters contained in the digest are subject + to the rules of the command using this structure. To find + the exact calculation refer to the actions in the command + using this structure. */ + TPM_MODIFIER_INDICATOR locality; /* The locality that called TPM_ExecuteTransport */ +} TPM_TRANSPORT_LOG_OUT; + +/* 13.5 TPM_TRANSPORT_AUTH structure rev 87 + + This structure provides the validation for the encrypted AuthData value. +*/ + +typedef struct tdTPM_TRANSPORT_AUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_AUTH */ +#endif + TPM_AUTHDATA authData; /* The AuthData value */ +} TPM_TRANSPORT_AUTH; + +/* 22.3 TPM_DAA_ISSUER rev 91 + + This structure is the abstract representation of non-secret settings controlling a DAA + context. The structure is required when loading public DAA data into a TPM. TPM_DAA_ISSUER + parameters are normally held outside the TPM as plain text data, and loaded into a TPM when a DAA + session is required. A TPM_DAA_ISSUER structure contains no integrity check: the TPM_DAA_ISSUER + structure at time of JOIN is indirectly verified by the issuer during the JOIN process, and a + digest of the verified TPM_DAA_ISSUER structure is held inside the TPM_DAA_TPM structure created + by the JOIN process. Parameters DAA_digest_X are digests of public DAA_generic_X parameters, and + used to verify that the correct value of DAA_generic_X has been loaded. DAA_generic_q is stored + in its native form to reduce command complexity. +*/ + +typedef struct tdTPM_DAA_ISSUER { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_ISSUER */ +#endif + TPM_DIGEST DAA_digest_R0; /* A digest of the parameter "R0", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_R1; /* A digest of the parameter "R1", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_S0; /* A digest of the parameter "S0", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_S1; /* A digest of the parameter "S1", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_n; /* A digest of the parameter "n", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_gamma; /* A digest of the parameter "gamma", which is not secret + and may be common to many TPMs. */ + BYTE DAA_generic_q[26]; /* The parameter q, which is not secret and may be common to + many TPMs. Note that q is slightly larger than a digest, + but is stored in its native form to simplify the + TPM_DAA_join command. Otherwise, JOIN requires 3 input + parameters. */ +} TPM_DAA_ISSUER; + +/* 22.4 TPM_DAA_TPM rev 91 + + This structure is the abstract representation of TPM specific parameters used during a DAA + context. TPM-specific DAA parameters may be stored outside the TPM, and hence this + structure is needed to save private DAA data from a TPM, or load private DAA data into a + TPM. + + If a TPM_DAA_TPM structure is stored outside the TPM, it is stored in a confidential format that + can be interpreted only by the TPM created it. This is to ensure that secret parameters are + rendered confidential, and that both secret and non-secret data in TPM_DAA_TPM form a + self-consistent set. + + TPM_DAA_TPM includes a digest of the public DAA parameters that were used during creation of the + TPM_DAA_TPM structure. This is needed to verify that a TPM_DAA_TPM is being used with the public + DAA parameters used to create the TPM_DAA_TPM structure. Parameters DAA_digest_v0 and + DAA_digest_v1 are digests of public DAA_private_v0 and DAA_private_v1 parameters, and used to + verify that the correct private parameters have been loaded. + + Parameter DAA_count is stored in its native form, because it is smaller than a digest, and is + required to enforce consistency. +*/ + +typedef struct tdTPM_DAA_TPM { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_TPM */ +#endif + TPM_DIGEST DAA_digestIssuer; /* A digest of a TPM_DAA_ISSUER structure that contains the + parameters used to generate this TPM_DAA_TPM + structure. */ + TPM_DIGEST DAA_digest_v0; /* A digest of the parameter "v0", which is secret and specific to + this TPM. "v0" is generated during a JOIN phase. */ + TPM_DIGEST DAA_digest_v1; /* A digest of the parameter "v1", which is secret and specific to + this TPM. "v1" is generated during a JOIN phase. */ + TPM_DIGEST DAA_rekey; /* A digest related to the rekeying process, which is not secret but + is specific to this TPM, and must be consistent across JOIN/SIGN + sessions. "rekey" is generated during a JOIN phase. */ + uint32_t DAA_count; /* The parameter "count", which is not secret but must be consistent + across JOIN/SIGN sessions. "count" is an input to the TPM from + the host system. */ +} TPM_DAA_TPM; + +/* 22.5 TPM_DAA_CONTEXT rev 91 + + TPM_DAA_CONTEXT structure is created and used inside a TPM, and never leaves the TPM. This + entire section is informative as the TPM does not expose this structure. TPM_DAA_CONTEXT + includes a digest of the public and private DAA parameters that were used during creation of the + TPM_DAA_CONTEXT structure. This is needed to verify that a TPM_DAA_CONTEXT is being used with the + public and private DAA parameters used to create the TPM_DAA_CONTEXT structure. +*/ + +typedef struct tdTPM_DAA_CONTEXT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_CONTEXT */ +#endif + TPM_DIGEST DAA_digestContext; /* A digest of parameters used to generate this + structure. The parameters vary, depending on whether the + session is a JOIN session or a SIGN session. */ + TPM_DIGEST DAA_digest; /* A running digest of certain parameters generated during DAA + computation; operationally the same as a PCR (which holds a + running digest of integrity metrics). */ + TPM_DAA_CONTEXT_SEED DAA_contextSeed; /* The seed used to generate other DAA + session parameters */ + BYTE DAA_scratch[256]; /* Memory used to hold different parameters at different + times of DAA computation, but only one parameter at a + time. The maximum size of this field is 256 bytes */ + BYTE DAA_stage; /* A counter, indicating the stage of DAA computation that was most + recently completed. The value of the counter is zero if the TPM + currently contains no DAA context. + + When set to zero (0) the TPM MUST clear all other fields in this + structure. + + The TPM MUST set DAA_stage to 0 on TPM_Startup(ANY) */ + TPM_BOOL DAA_scratch_null; +} TPM_DAA_CONTEXT; + +/* 22.6 TPM_DAA_JOINDATA rev 91 + + This structure is the abstract representation of data that exists only during a specific JOIN + session. +*/ + +typedef struct tdTPM_DAA_JOINDATA { + BYTE DAA_join_u0[128]; /* A TPM-specific secret "u0", used during the JOIN phase, + and discarded afterwards. */ + BYTE DAA_join_u1[138]; /* A TPM-specific secret "u1", used during the JOIN phase, + and discarded afterwards. */ + TPM_DIGEST DAA_digest_n0; /* A digest of the parameter "n0", which is an RSA public key with + exponent 2^16 +1 */ +} TPM_DAA_JOINDATA; + +/* DAA Session structure + +*/ + +#ifdef TPM_MIN_DAA_SESSIONS +#if (TPM_MIN_DAA_SESSIONS < 1) +#error "TPM_MIN_DAA_SESSIONS minimum is 1" +#endif +#endif + +#ifndef TPM_MIN_DAA_SESSIONS +#define TPM_MIN_DAA_SESSIONS 1 +#endif + +typedef struct tdTPM_DAA_SESSION_DATA { + TPM_DAA_ISSUER DAA_issuerSettings; /* A set of DAA issuer parameters controlling a DAA + session. (non-secret) */ + TPM_DAA_TPM DAA_tpmSpecific; /* A set of DAA parameters associated with a + specific TPM. (secret) */ + TPM_DAA_CONTEXT DAA_session; /* A set of DAA parameters associated with a DAA + session. (secret) */ + TPM_DAA_JOINDATA DAA_joinSession; /* A set of DAA parameters used only during the JOIN + phase of a DAA session, and generated by the + TPM. (secret) */ + /* added kgold */ + TPM_HANDLE daaHandle; /* DAA session handle */ + TPM_BOOL valid; /* array entry is valid */ + /* FIXME should have handle type Join or Sign */ +} TPM_DAA_SESSION_DATA; + +/* 22.8 TPM_DAA_BLOB rev 98 + + The structure passed during the join process +*/ + +typedef struct tdTPM_DAA_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_BLOB */ +#endif + TPM_RESOURCE_TYPE resourceType; /* The resource type: enc(DAA_tpmSpecific) or enc(v0) or + enc(v1) */ + BYTE label[16]; /* Label for identification of the blob. Free format + area. */ + TPM_DIGEST blobIntegrity; /* The integrity of the entire blob including the sensitive + area. This is a HMAC calculation with the entire + structure (including sensitiveData) being the hash and + daaProof is the secret */ + TPM_SIZED_BUFFER additionalData; /* Additional information set by the TPM that helps define + and reload the context. The information held in this area + MUST NOT expose any information held in shielded + locations. This should include any IV for symmetric + encryption */ + TPM_SIZED_BUFFER sensitiveData; /* A TPM_DAA_SENSITIVE structure */ +#if 0 + uint32_t additionalSize; + [size_is(additionalSize)] BYTE* additionalData; + uint32_t sensitiveSize; + [size_is(sensitiveSize)] BYTE* sensitiveData; +#endif +} TPM_DAA_BLOB; + +/* 22.9 TPM_DAA_SENSITIVE rev 91 + + The encrypted area for the DAA parameters +*/ + +typedef struct tdTPM_DAA_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_SENSITIVE */ +#endif + TPM_SIZED_BUFFER internalData; /* DAA_tpmSpecific or DAA_private_v0 or DAA_private_v1 */ +#if 0 + uint32_t internalSize; + [size_is(internalSize)] BYTE* internalData; +#endif +} TPM_DAA_SENSITIVE; + +/* 7.1 TPM_PERMANENT_FLAGS rev 110 + + These flags maintain state information for the TPM. The values are not affected by any + TPM_Startup command. + + The flag history includes: + + Rev 62 specLevel 1 errataRev 0: 15 BOOLs + Rev 85 specLevel 2 errataRev 0: 19 BOOLs + Added: nvLocked, readSRKPub, tpmEstablished, maintenanceDone + Rev 94 specLevel 2 errataRev 1: 19 BOOLs + Rev 103 specLevel 2 errataRev 2: 20 BOOLs + Added: disableFullDALogicInfo +*/ + +typedef struct tdTPM_PERMANENT_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_PERMANENT_FLAGS */ +#endif + TPM_BOOL disable; /* disable The state of the disable flag. The default state is TRUE + */ + TPM_BOOL ownership; /* The ability to install an owner. The default state is TRUE. */ + TPM_BOOL deactivated; /* The state of the inactive flag. The default state is TRUE. */ + TPM_BOOL readPubek; /* The ability to read the PUBEK without owner authorization. The + default state is TRUE. + + set TRUE on owner clear + set FALSE on take owner, disablePubekRead + */ + TPM_BOOL disableOwnerClear; /* Whether the owner authorized clear commands are active. The + default state is FALSE. */ + TPM_BOOL allowMaintenance; /* Whether the TPM Owner may create a maintenance archive. The + default state is TRUE. */ + TPM_BOOL physicalPresenceLifetimeLock; /* This bit can only be set to TRUE; it cannot be set to + FALSE except during the manufacturing process. + + FALSE: The state of either physicalPresenceHWEnable or + physicalPresenceCMDEnable MAY be changed. (DEFAULT) + + TRUE: The state of either physicalPresenceHWEnable or + physicalPresenceCMDEnable MUST NOT be changed for the + life of the TPM. */ + TPM_BOOL physicalPresenceHWEnable; /* FALSE: Disable the hardware signal indicating physical + presence. (DEFAULT) + + TRUE: Enables the hardware signal indicating physical + presence. */ + TPM_BOOL physicalPresenceCMDEnable; /* FALSE: Disable the command indicating physical + presence. (DEFAULT) + + TRUE: Enables the command indicating physical + presence. */ + TPM_BOOL CEKPUsed; /* TRUE: The PRIVEK and PUBEK were created using + TPM_CreateEndorsementKeyPair. + + FALSE: The PRIVEK and PUBEK were created using a manufacturer's + process. NOTE: This flag has no default value as the key pair + MUST be created by one or the other mechanism. */ + TPM_BOOL TPMpost; /* TRUE: After TPM_Startup, if there is a call to + TPM_ContinueSelfTest the TPM MUST execute the actions of + TPM_SelfTestFull + + FALSE: After TPM_Startup, if there is a call to + TPM_ContinueSelfTest the TPM MUST execute TPM_ContinueSelfTest + + If the TPM supports the implicit invocation of + TPM_ContinueSelftTest upon the use of an untested resource, the + TPM MUST use the TPMPost flag to call either TPM_ContinueSelfTest + or TPM_SelfTestFull + + The TPM manufacturer sets this bit during TPM manufacturing and + the bit is unchangeable after shipping the TPM + + The default state is FALSE */ + TPM_BOOL TPMpostLock; /* With the clarification of TPMPost TPMpostLock is now + unnecessary. + This flag is now deprecated */ + TPM_BOOL FIPS; /* TRUE: This TPM operates in FIPS mode + FALSE: This TPM does NOT operate in FIPS mode */ + TPM_BOOL tpmOperator; /* TRUE: The operator authorization value is valid + FALSE: the operator authorization value is not set */ + TPM_BOOL enableRevokeEK; /* TRUE: The TPM_RevokeTrust command is active + FALSE: the TPM RevokeTrust command is disabled */ + TPM_BOOL nvLocked; /* TRUE: All NV area authorization checks are active + FALSE: No NV area checks are performed, except for maxNVWrites. + FALSE is the default value */ + TPM_BOOL readSRKPub; /* TRUE: GetPubKey will return the SRK pub key + FALSE: GetPubKey will not return the SRK pub key + Default SHOULD be FALSE */ + TPM_BOOL tpmEstablished; /* TRUE: TPM_HASH_START has been executed at some time + FALSE: TPM_HASH_START has not been executed at any time + Default is FALSE - resets using TPM_ResetEstablishmentBit */ + TPM_BOOL maintenanceDone; /* TRUE: A maintenance archive has been created for the current + SRK */ +#if (TPM_REVISION >= 103) /* added for rev 103 */ + TPM_BOOL disableFullDALogicInfo; /* TRUE: The full dictionary attack TPM_GetCapability info is + deactivated. The returned structure is TPM_DA_INFO_LIMITED. + FALSE: The full dictionary attack TPM_GetCapability info is + activated. The returned structure is TPM_DA_INFO. + Default is FALSE. + */ +#endif + /* NOTE: Cannot add vendor specific flags here, since TPM_GetCapability() returns the serialized + structure */ +} TPM_PERMANENT_FLAGS; + +/* 7.2 TPM_STCLEAR_FLAGS rev 109 + + These flags maintain state that is reset on each TPM_Startup(ST_Clear) command. The values are + not affected by TPM_Startup(ST_State) commands. +*/ + +typedef struct tdTPM_STCLEAR_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STCLEAR_FLAGS */ +#endif + TPM_BOOL deactivated; /* Prevents the operation of most capabilities. There is no + default state. It is initialized by TPM_Startup to the + same value as TPM_PERMANENT_FLAGS -> + deactivated. TPM_SetTempDeactivated sets it to TRUE. */ + TPM_BOOL disableForceClear; /* Prevents the operation of TPM_ForceClear when TRUE. The + default state is FALSE. TPM_DisableForceClear sets it to + TRUE. */ + TPM_BOOL physicalPresence; /* Command assertion of physical presence. The default state + is FALSE. This flag is affected by the + TSC_PhysicalPresence command but not by the hardware + signal. */ + TPM_BOOL physicalPresenceLock; /* Indicates whether changes to the TPM_STCLEAR_FLAGS -> + physicalPresence flag are permitted. + TPM_Startup(ST_CLEAR) sets PhysicalPresenceLock to its + default state of FALSE (allow changes to the + physicalPresence flag). When TRUE, the physicalPresence + flag is FALSE. TSC_PhysicalPresence can change the state + of physicalPresenceLock. */ + TPM_BOOL bGlobalLock; /* Set to FALSE on each TPM_Startup(ST_CLEAR). Set to TRUE + when a write to NV_Index =0 is successful */ + /* NOTE: Cannot add vendor specific flags here, since TPM_GetCapability() returns the serialized + structure */ +} TPM_STCLEAR_FLAGS; + + +/* 7.3 TPM_STANY_FLAGS rev 87 + + These flags reset on any TPM_Startup command. +*/ + +typedef struct tdTPM_STANY_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STANY_FLAGS */ +#endif + TPM_BOOL postInitialise; /* Prevents the operation of most capabilities. There is no default + state. It is initialized by TPM_Init to TRUE. TPM_Startup sets it + to FALSE. */ + TPM_MODIFIER_INDICATOR localityModifier; /*This SHALL indicate for each command the presence of + a locality modifier for the command. It MUST be set + to NULL after the TPM executes each command. */ +#if 0 + TPM_BOOL transportExclusive; /* Defaults to FALSE. TRUE when there is an exclusive transport + session active. Execution of ANY command other than + TPM_ExecuteTransport or TPM_ReleaseTransportSigned MUST + invalidate the exclusive transport session. */ +#endif + TPM_TRANSHANDLE transportExclusive; /* Defaults to 0x00000000, Set to the handle when an + exclusive transport session is active */ + TPM_BOOL TOSPresent; /* Defaults to FALSE + Set to TRUE on TPM_HASH_START + set to FALSE using setCapability */ + /* NOTE: Added kgold */ + TPM_BOOL stateSaved; /* Defaults to FALSE + Set to TRUE on TPM_SaveState + Set to FALSE on any other ordinal + + This is an optimization flag, so the file need not be deleted if + it does not exist. + */ +} TPM_STANY_FLAGS; + +/* 7.4 TPM_PERMANENT_DATA rev 105 + + This structure contains the data fields that are permanently held in the TPM and not affected by + TPM_Startup(any). + + Many of these fields contain highly confidential and privacy sensitive material. The TPM must + maintain the protections around these fields. +*/ + +#ifdef TPM_MIN_COUNTERS +#if (TPM_MIN_COUNTERS < 4) +#error "TPM_MIN_COUNTERS minimum is 4" +#endif +#endif + +#ifndef TPM_MIN_COUNTERS +#define TPM_MIN_COUNTERS 4 /* the minimum number of counters is 4 */ +#endif + +#define TPM_DELEGATE_KEY TPM_KEY +#define TPM_MAX_NV_WRITE_NOOWNER 64 + +/* Although the ordinal is 32 bits, only the lower 8 bits seem to be used. So for now, define an + array of 256/8 bytes for ordinalAuditStatus - kgold */ + +#define TPM_ORDINALS_MAX 256 /* assumes a multiple of CHAR_BIT */ +#define TPM_AUTHDIR_SIZE 1 /* Number of DIR registers */ + + + + +typedef struct tdTPM_PERMANENT_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_PERMANENT_DATA */ +#endif + BYTE revMajor; /* This is the TPM major revision indicator. This SHALL be set by + the TPME, only. The default value is manufacturer-specific. */ + BYTE revMinor; /* This is the TPM minor revision indicator. This SHALL be set by + the TPME, only. The default value is manufacturer-specific. */ + TPM_SECRET tpmProof; /* This is a random number that each TPM maintains to validate blobs + in the SEAL and other processes. The default value is + manufacturer-specific. */ + TPM_NONCE EKReset; /* Nonce held by TPM to validate TPM_RevokeTrust. This value is set + as the next 20 bytes from the TPM RNG when the EK is set + (was fipsReset - kgold) */ + TPM_SECRET ownerAuth; /* This is the TPM-Owner's authorization data. The default value is + manufacturer-specific. */ + TPM_SECRET operatorAuth; /* The value that allows the execution of the SetTempDeactivated + command */ + TPM_DIRVALUE authDIR; /* The array of TPM Owner authorized DIR. Points to the same + location as the NV index value. (kgold - was array of 1) */ +#ifndef TPM_NOMAINTENANCE + TPM_PUBKEY manuMaintPub; /* This is the manufacturer's public key to use in the maintenance + operations. The default value is manufacturer-specific. */ +#endif + TPM_KEY endorsementKey; /* This is the TPM's endorsement key pair. */ + TPM_KEY srk; /* This is the TPM's StorageRootKey. */ + TPM_SYMMETRIC_KEY_TOKEN contextKey; /* This is the key in use to perform context saves. The key + may be symmetric or asymmetric. The key size is + predicated by the algorithm in use. */ + TPM_SYMMETRIC_KEY_TOKEN delegateKey; /* This key encrypts delegate rows that are stored + outside the TPM. */ + TPM_COUNTER_VALUE auditMonotonicCounter; /* This SHALL be the audit monotonic counter for the + TPM. This value starts at 0 and increments + according to the rules of auditing */ + TPM_COUNTER_VALUE monotonicCounter[TPM_MIN_COUNTERS]; /* This SHALL be the monotonic + counters for the TPM. The + individual counters start and + increment according to the rules + of monotonic counters. */ + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; /* The attributes for all of the PCR registers + supported by the TPM. */ + BYTE ordinalAuditStatus[TPM_ORDINALS_MAX/CHAR_BIT]; /* Table indicating which ordinals are being + audited. */ +#if 0 + /* kgold - The xcrypto RNG is good enough that this is not needed */ + BYTE* rngState; /* State information describing the random number + generator. */ +#endif + TPM_FAMILY_TABLE familyTable; /* The family table in use for delegations */ + TPM_DELEGATE_TABLE delegateTable; /* The delegate table */ + uint32_t lastFamilyID; /* A value that sets the high water mark for family ID's. Set to 0 + during TPM manufacturing and never reset. */ + uint32_t noOwnerNVWrite; /* The count of NV writes that have occurred when there is no TPM + Owner. + + This value starts at 0 in manufacturing and after each + TPM_OwnerClear. If the value exceeds 64 the TPM returns + TPM_MAXNVWRITES to any command attempting to manipulate the NV + storage. */ + TPM_CMK_DELEGATE restrictDelegate; /* The settings that allow for the delegation and + use on CMK keys. Default value is false. */ + TPM_DAA_TPM_SEED tpmDAASeed; /* This SHALL be a random value generated after generation + of the EK. + + tpmDAASeed does not change during TPM Owner changes. If + the EK is removed (RevokeTrust) then the TPM MUST + invalidate the tpmDAASeed. The owner can force a change + in the value through TPM_SetCapability. + + (linked to daaProof) */ + TPM_NONCE daaProof; /* This is a random number that each TPM maintains to validate blobs + in the DAA processes. The default value is manufacturer-specific. + + The value is not changed when the owner is changed. It is + changed when the EK changes. The owner can force a change in the + value through TPM_SetCapability. */ + TPM_SYMMETRIC_KEY_TOKEN daaBlobKey; /* This is the key in use to perform DAA encryption and + decryption. The key may be symmetric or asymmetric. The + key size is predicated by the algorithm in use. + + This value MUST be changed when daaProof changes. + + This key MUST NOT be a copy of the EK or SRK. + + (linked to daaProof) */ + /* NOTE: added kgold */ + TPM_BOOL ownerInstalled; /* TRUE: The TPM has an owner installed. + FALSE: The TPM has no owner installed. (default) */ + BYTE tscOrdinalAuditStatus; /* extra byte to track TSC ordinals */ + TPM_BOOL allowLoadMaintPub; /* TRUE allows the TPM_LoadManuMaintPub command */ + +} TPM_PERMANENT_DATA; + +/* 7.6 TPM_STANY_DATA */ + +#ifdef TPM_MIN_AUTH_SESSIONS +#if (TPM_MIN_AUTH_SESSIONS < 3) +#error "TPM_MIN_AUTH_SESSIONS minimum is 3" +#endif +#endif + +#ifndef TPM_MIN_AUTH_SESSIONS +#define TPM_MIN_AUTH_SESSIONS 3 +#endif + +/* NOTE: Vendor specific */ + +typedef struct tdTPM_AUTH_SESSION_DATA { + /* vendor specific */ + TPM_AUTHHANDLE handle; /* Handle for a session */ + TPM_PROTOCOL_ID protocolID; /* TPM_PID_OIAP, TPM_PID_OSAP, TPM_PID_DSAP */ + TPM_ENT_TYPE entityTypeByte; /* The type of entity in use (TPM_ET_SRK, TPM_ET_OWNER, + TPM_ET_KEYHANDLE ... */ + TPM_ADIP_ENC_SCHEME adipEncScheme; /* ADIP encryption scheme */ + TPM_NONCE nonceEven; /* OIAP, OSAP, DSAP */ + TPM_SECRET sharedSecret; /* OSAP */ + TPM_DIGEST entityDigest; /* OSAP tracks which entity established the OSAP session */ + TPM_DELEGATE_PUBLIC pub; /* DSAP */ + TPM_BOOL valid; /* added kgold: array entry is valid */ +} TPM_AUTH_SESSION_DATA; + + +/* 3. contextList MUST support a minimum of 16 entries, it MAY support more. */ + +#ifdef TPM_MIN_SESSION_LIST +#if (TPM_MIN_SESSION_LIST < 16) +#error "TPM_MIN_SESSION_LIST minimum is 16" +#endif +#endif + +#ifndef TPM_MIN_SESSION_LIST +#define TPM_MIN_SESSION_LIST 16 +#endif + +/* 7.5 TPM_STCLEAR_DATA rev 101 + + This is an informative structure and not normative. It is purely for convenience of writing the + spec. + + Most of the data in this structure resets on TPM_Startup(ST_Clear). A TPM may implement rules + that provide longer-term persistence for the data. The TPM reflects how it handles the data in + various TPM_GetCapability fields including startup effects. +*/ + +typedef struct tdTPM_STCLEAR_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STCLEAR_DATA */ +#endif + TPM_NONCE contextNonceKey; /* This is the nonce in use to properly identify saved key context + blobs This SHALL be set to all zeros on each TPM_Startup + (ST_Clear). + */ + TPM_COUNT_ID countID; /* This is the handle for the current monotonic counter. This SHALL + be set to zero on each TPM_Startup(ST_Clear). */ + uint32_t ownerReference; /* Points to where to obtain the owner secret in OIAP and OSAP + commands. This allows a TSS to manage 1.1 applications on a 1.2 + TPM where delegation is in operation. */ + TPM_BOOL disableResetLock; /* Disables TPM_ResetLockValue upon authorization failure. + The value remains TRUE for the timeout period. + + Default is FALSE. + + The value is in the STCLEAR_DATA structure as the + implementation of this flag is TPM vendor specific. */ + TPM_PCRVALUE PCRS[TPM_NUM_PCR]; /* Platform configuration registers */ +#if (TPM_REVISION >= 103) /* added for rev 103 */ + uint32_t deferredPhysicalPresence; /* The value can save the assertion of physicalPresence. + Individual bits indicate to its ordinal that + physicalPresence was previously asserted when the + software state is such that it can no longer be asserted. + Set to zero on each TPM_Startup(ST_Clear). */ +#endif + /* NOTE: Added for dictionary attack mitigation */ + uint32_t authFailCount; /* number of authorization failures without a TPM_ResetLockValue */ + uint32_t authFailTime; /* time of threshold failure in seconds */ + /* NOTE: Moved from TPM_STANY_DATA. Saving this state is optional. This implementation + does. */ + TPM_AUTH_SESSION_DATA authSessions[TPM_MIN_AUTH_SESSIONS]; /* List of current + sessions. Sessions can be OSAP, + OIAP, DSAP and Transport */ + /* NOTE: Added for transport */ + TPM_TRANSPORT_INTERNAL transSessions[TPM_MIN_TRANS_SESSIONS]; + /* 22.7 TPM_STANY_DATA Additions (for DAA) - moved to TPM_STCLEAR_DATA for startup state */ + TPM_DAA_SESSION_DATA daaSessions[TPM_MIN_DAA_SESSIONS]; + /* 1. The group of contextNonceSession, contextCount, contextList MUST reset at the same + time. */ + TPM_NONCE contextNonceSession; /* This is the nonce in use to properly identify saved + session context blobs. This MUST be set to all zeros on + each TPM_Startup (ST_Clear). The nonce MAY be set to + null on TPM_Startup( any). */ + uint32_t contextCount; /* This is the counter to avoid session context blob replay + attacks. This MUST be set to 0 on each TPM_Startup + (ST_Clear). The value MAY be set to 0 on TPM_Startup + (any). */ + uint32_t contextList[TPM_MIN_SESSION_LIST]; /* This is the list of outstanding session blobs. + All elements of this array MUST be set to 0 on + each TPM_Startup (ST_Clear). The values MAY be + set to 0 on TPM_Startup (any). */ + /* NOTE Added auditDigest effect, saved with ST_STATE */ + TPM_DIGEST auditDigest; /* This is the extended value that is the audit log. This + SHALL be set to all zeros at the start of each audit + session. */ + /* NOTE Storage for the ordinal response */ + TPM_STORE_BUFFER ordinalResponse; /* outgoing response buffer for this ordinal */ +} TPM_STCLEAR_DATA; + +/* 7.6 TPM_STANY_DATA rev 87 + + This is an informative structure and not normative. It is purely for convenience of writing the + spec. + + Most of the data in this structure resets on TPM_Startup(ST_State). A TPM may implement rules + that provide longer-term persistence for the data. The TPM reflects how it handles the data in + various getcapability fields including startup effects. +*/ + +typedef struct tdTPM_STANY_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STANY_DATA */ +#endif + TPM_CURRENT_TICKS currentTicks; /* This is the current tick counter. This is reset to 0 + according to the rules when the TPM can tick. See the + section on the tick counter for details. */ +} TPM_STANY_DATA; + +/* 11. Signed Structures */ + +/* 11.1 TPM_CERTIFY_INFO rev 101 + + When the TPM certifies a key, it must provide a signature with a TPM identity key on information + that describes that key. This structure provides the mechanism to do so. + + Key usage and keyFlags must have their upper byte set to zero to avoid collisions with the other + signature headers. +*/ + +typedef struct tdTPM_CERTIFY_INFO { + TPM_STRUCT_VER version; /* This MUST be 1.1.0.0 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified. The + upper byte MUST be zero */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be set to the same value as the corresponding + parameter in the TPM_KEY structure that describes the + public key that is being certified. The upper byte MUST + be zero */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_DIGEST pubkeyDigest; /* This SHALL be a digest of the value TPM_KEY -> pubKey -> + key in a TPM_KEY representation of the key to be + certified */ + TPM_NONCE data; /* This SHALL be externally provided data. */ + TPM_BOOL parentPCRStatus; /* This SHALL indicate if any parent key was wrapped to a + PCR */ + TPM_SIZED_BUFFER pcrInfo; /* */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the size of the pcrInfo parameter. A value + of zero indicates that the key is not wrapped to a PCR */ + BYTE* PCRInfo; /* This SHALL be the TPM_PCR_INFO structure. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_pcr_info; +} TPM_CERTIFY_INFO; + +/* 11.2 TPM_CERTIFY_INFO2 rev 101 + + When the TPM certifies a key, it must provide a signature with a TPM identity key on information + that describes that key. This structure provides the mechanism to do so. + + Key usage and keyFlags must have their upper byte set to zero to avoid collisions with the other + signature headers. +*/ + +typedef struct tdTPM_CERTIFY_INFO2 { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CERTIFY_INFO2 */ +#endif + BYTE fill; /* MUST be 0x00 */ + TPM_PAYLOAD_TYPE payloadType; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified. The + upper byte MUST be zero */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be set to the same value as the corresponding + parameter in the TPM_KEY structure that describes the + public key that is being certified. The upper byte MUST + be zero. */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_DIGEST pubkeyDigest; /* This SHALL be a digest of the value TPM_KEY -> pubKey -> + key in a TPM_KEY representation of the key to be + certified */ + TPM_NONCE data; /* This SHALL be externally provided data. */ + TPM_BOOL parentPCRStatus; /* This SHALL indicate if any parent key was wrapped to a + PCR */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the size of the pcrInfo parameter. A value + of zero indicates that the key is not wrapped to a PCR */ + BYTE* PCRInfo; /* This SHALL be the TPM_PCR_INFO_SHORT structure. */ +#endif + TPM_SIZED_BUFFER pcrInfo; +#if 0 + uint32_t migrationAuthoritySize; /* This SHALL be the size of migrationAuthority */ + BYTE *migrationAuthority; /* If the key to be certified has [payload == + TPM_PT_MIGRATE_RESTRICTED or payload + ==TPM_PT_MIGRATE_EXTERNAL], migrationAuthority is the + digest of the TPM_MSA_COMPOSITE and has TYPE == + TPM_DIGEST. Otherwise it is NULL. */ +#endif + TPM_SIZED_BUFFER migrationAuthority; + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO_SHORT *tpm_pcr_info_short; +} TPM_CERTIFY_INFO2; + +/* 11.3 TPM_QUOTE_INFO rev 87 + + This structure provides the mechanism for the TPM to quote the current values of a list of PCRs. +*/ + +typedef struct tdTPM_QUOTE_INFO { + TPM_STRUCT_VER version; /* This MUST be 1.1.0.0 */ + BYTE fixed[4]; /* This SHALL always be the string 'QUOT' */ + TPM_COMPOSITE_HASH digestValue; /* This SHALL be the result of the composite hash algorithm + using the current values of the requested PCR indices. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data */ +} TPM_QUOTE_INFO; + +/* 11.4 TPM_QUOTE_INFO2 rev 87 + + This structure provides the mechanism for the TPM to quote the current values of a list of PCRs. +*/ + +typedef struct tdTPM_QUOTE_INFO2 { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_QUOTE_INFO2 */ +#endif + BYTE fixed[4]; /* This SHALL always be the string 'QUT2' */ + TPM_NONCE externalData; /* 160 bits of externally supplied data */ + TPM_PCR_INFO_SHORT infoShort; /* */ +} TPM_QUOTE_INFO2; + +/* 12.1 TPM_EK_BLOB rev 87 + + This structure provides a wrapper to each type of structure that will be in use when the + endorsement key is in use. +*/ + +typedef struct tdTPM_EK_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB */ +#endif + TPM_EK_TYPE ekType; /* This SHALL be set to reflect the type of blob in use */ + TPM_SIZED_BUFFER blob; /* The blob of information depending on the type */ +#if 0 + uint32_t blobSize; /* */ + [size_is(blobSize)] byte* blob; /* */ +#endif +} TPM_EK_BLOB; + +/* 12.2 TPM_EK_BLOB_ACTIVATE rev 87 + + This structure contains the symmetric key to encrypt the identity credential. This structure + always is contained in a TPM_EK_BLOB. +*/ + +typedef struct tdTPM_EK_BLOB_ACTIVATE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB_ACTIVATE */ +#endif + TPM_SYMMETRIC_KEY sessionKey; /* This SHALL be the session key used by the CA to encrypt + the TPM_IDENTITY_CREDENTIAL */ + TPM_DIGEST idDigest; /* This SHALL be the digest of the TPM identity public key + that is being certified by the CA */ + TPM_PCR_INFO_SHORT pcrInfo; /* This SHALL indicate the PCR's and localities */ +} TPM_EK_BLOB_ACTIVATE; + +/* 12.3 TPM_EK_BLOB_AUTH rev 87 + + This structure contains the symmetric key to encrypt the identity credential. This structure + always is contained in a TPM_EK_BLOB. +*/ + +typedef struct tdTPM_EK_BLOB_AUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB_AUTH */ +#endif + TPM_SECRET authValue; /* This SHALL be the authorization value */ +} TPM_EK_BLOB_AUTH; + +/* 12.5 TPM_IDENTITY_CONTENTS rev 87 + + TPM_MakeIdentity uses this structure and the signature of this structure goes to a privacy CA + during the certification process. +*/ + +typedef struct tdTPM_IDENTITY_CONTENTS { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + uint32_t ordinal; /* This SHALL be the ordinal of the TPM_MakeIdentity + command. */ + TPM_CHOSENID_HASH labelPrivCADigest; /* This SHALL be the result of hashing the chosen + identityLabel and privacyCA for the new TPM + identity */ + TPM_PUBKEY identityPubKey; /* This SHALL be the public key structure of the identity + key */ +} TPM_IDENTITY_CONTENTS; + +/* 12.8 TPM_ASYM_CA_CONTENTS rev 87 + + This structure contains the symmetric key to encrypt the identity credential. +*/ + +typedef struct tdTPM_ASYM_CA_CONTENTS { + TPM_SYMMETRIC_KEY sessionKey; /* This SHALL be the session key used by the CA to encrypt + the TPM_IDENTITY_CREDENTIAL */ + TPM_DIGEST idDigest; /* This SHALL be the digest of the TPM_PUBKEY of the key + that is being certified by the CA */ +} TPM_ASYM_CA_CONTENTS; + +/* + 14. Audit Structures +*/ + +/* 14.1 TPM_AUDIT_EVENT_IN rev 87 + + This structure provides the auditing of the command upon receipt of the command. It provides the + information regarding the input parameters. +*/ + +typedef struct tdTPM_AUDIT_EVENT_IN { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_AUDIT_EVENT_IN */ +#endif + TPM_DIGEST inputParms; /* Digest value according to the HMAC digest rules of the + "above the line" parameters (i.e. the first HMAC digest + calculation). When there are no HMAC rules, the input + digest includes all parameters including and after the + ordinal. */ + TPM_COUNTER_VALUE auditCount; /* The current value of the audit monotonic counter */ +} TPM_AUDIT_EVENT_IN; + +/* 14.2 TPM_AUDIT_EVENT_OUT rev 87 + + This structure reports the results of the command execution. It includes the return code and the + output parameters. +*/ + +typedef struct tdTPM_AUDIT_EVENT_OUT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_AUDIT_EVENT_OUT */ +#endif + TPM_DIGEST outputParms; /* Digest value according to the HMAC digest rules of the + "above the line" parameters (i.e. the first HMAC digest + calculation). When there are no HMAC rules, the output + digest includes the return code, the ordinal, and all + parameters after the return code. */ + TPM_COUNTER_VALUE auditCount; /* The current value of the audit monotonic counter */ +} TPM_AUDIT_EVENT_OUT; + +/* + 18. Context structures +*/ + +/* 18.1 TPM_CONTEXT_BLOB rev 102 + + This is the header for the wrapped context. The blob contains all information necessary to reload + the context back into the TPM. + + The additional data is used by the TPM manufacturer to save information that will assist in the + reloading of the context. This area must not contain any shielded data. For instance, the field + could contain some size information that allows the TPM more efficient loads of the context. The + additional area could not contain one of the primes for a RSA key. + + To ensure integrity of the blob when using symmetric encryption the TPM vendor could use some + valid cipher chaining mechanism. To ensure the integrity without depending on correct + implementation, the TPM_CONTEXT_BLOB structure uses a HMAC of the entire structure using tpmProof + as the secret value. + + Since both additionalData and sensitiveData are informative, any or all of additionalData + could be moved to sensitiveData. +*/ + +#define TPM_CONTEXT_LABEL_SIZE 16 + +typedef struct tdTPM_CONTEXT_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CONTEXTBLOB */ +#endif + TPM_RESOURCE_TYPE resourceType; /* The resource type */ + TPM_HANDLE handle; /* Previous handle of the resource */ + BYTE label[TPM_CONTEXT_LABEL_SIZE]; /* Label for identification of the blob. Free format + area. */ + uint32_t contextCount; /* MUST be TPM_STANY_DATA -> contextCount when creating the + structure. This value is ignored for context blobs that + reference a key. */ + TPM_DIGEST integrityDigest; /* The integrity of the entire blob including the sensitive + area. This is a HMAC calculation with the entire + structure (including sensitiveData) being the hash and + tpmProof is the secret */ +#if 0 + uint32_t additionalSize; + [size_is(additionalSize)] BYTE* additionalData; + uint32_t sensitiveSize; + [size_is(sensitiveSize)] BYTE* sensitiveData; +#endif + TPM_SIZED_BUFFER additionalData; /* Additional information set by the TPM that helps define + and reload the context. The information held in this area + MUST NOT expose any information held in shielded + locations. This should include any IV for symmetric + encryption */ + TPM_SIZED_BUFFER sensitiveData; /* The normal information for the resource that can be + exported */ +} TPM_CONTEXT_BLOB; + +/* 18.2 TPM_CONTEXT_SENSITIVE rev 87 + + The internal areas that the TPM needs to encrypt and store off the TPM. + + This is an informative structure and the TPM can implement in any manner they wish. +*/ + +typedef struct tdTPM_CONTEXT_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CONTEXT_SENSITIVE */ +#endif + TPM_NONCE contextNonce; /* On context blobs other than keys this MUST be + TPM_STANY_DATA - > contextNonceSession For keys the value + is TPM_STCLEAR_DATA -> contextNonceKey */ +#if 0 + uint32_t internalSize; + [size_is(internalSize)] BYTE* internalData; +#endif + TPM_SIZED_BUFFER internalData; /* The internal data area */ +} TPM_CONTEXT_SENSITIVE; + +/* 19.2 TPM_NV_ATTRIBUTES rev 99 + + This structure allows the TPM to keep track of the data and permissions to manipulate the area. +*/ + +typedef struct tdTPM_NV_ATTRIBUTES { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_NV_ATTRIBUTES */ +#endif + uint32_t attributes; /* The attribute area */ +} TPM_NV_ATTRIBUTES; + +/* 19.3 TPM_NV_DATA_PUBLIC rev 110 + + This structure represents the public description and controls on the NV area. + + bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at TPM_Startup(ST_Clear). + bWriteDefine is persistent, in that it remains TRUE through startup. + + A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is not + required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the digest + can return zero. A TPM that does store the digest may return either the digest or zero. +*/ + +typedef struct tdTPM_NV_DATA_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_NV_DATA_PUBLIC */ +#endif + TPM_NV_INDEX nvIndex; /* The index of the data area */ + TPM_PCR_INFO_SHORT pcrInfoRead; /* The PCR selection that allows reading of the area */ + TPM_PCR_INFO_SHORT pcrInfoWrite; /* The PCR selection that allows writing of the area */ + TPM_NV_ATTRIBUTES permission; /* The permissions for manipulating the area */ + TPM_BOOL bReadSTClear; /* Set to FALSE on each TPM_Startup(ST_Clear) and set to + TRUE after a ReadValuexxx with datasize of 0 */ + TPM_BOOL bWriteSTClear; /* Set to FALSE on each TPM_Startup(ST_CLEAR) and set to + TRUE after a WriteValuexxx with a datasize of 0. */ + TPM_BOOL bWriteDefine; /* Set to FALSE after TPM_NV_DefineSpace and set to TRUE + after a successful WriteValuexxx with a datasize of 0 */ + uint32_t dataSize; /* The size of the data area in bytes */ +} TPM_NV_DATA_PUBLIC; + +/* 19.4 TPM_NV_DATA_SENSITIVE rev 101 + + This is an internal structure that the TPM uses to keep the actual NV data and the controls + regarding the area. +*/ + +typedef struct tdTPM_NV_DATA_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_NV_DATA_SENSITIVE */ +#endif + TPM_NV_DATA_PUBLIC pubInfo; /* The public information regarding this area */ + TPM_AUTHDATA authValue; /* The authorization value to manipulate the value */ + BYTE *data; /* The data area. This MUST not contain any sensitive information as + the TPM does not provide any confidentiality on the data. */ + /* NOTE Added kg */ + TPM_DIGEST digest; /* for OSAP comparison */ +} TPM_NV_DATA_SENSITIVE; + +typedef struct tdTPM_NV_INDEX_ENTRIES { + uint32_t nvIndexCount; /* number of entries */ + TPM_NV_DATA_SENSITIVE *tpm_nvindex_entry; /* array of TPM_NV_DATA_SENSITIVE */ +} TPM_NV_INDEX_ENTRIES; + +/* TPM_NV_DATA_ST + + This is a cache of the the NV defined space volatile flags, used during error rollback +*/ + +typedef struct tdTPM_NV_DATA_ST { + TPM_NV_INDEX nvIndex; /* The index of the data area */ + TPM_BOOL bReadSTClear; + TPM_BOOL bWriteSTClear; +} TPM_NV_DATA_ST; + +/* + 21. Capability areas +*/ + +/* 21.6 TPM_CAP_VERSION_INFO rev 99 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_VERSION_VAL request. TPM returns + the current version and revision of the TPM. + + The specLevel and errataRev are defined in the document "Specification and File Naming + Conventions" + + The tpmVendorID is a value unique to each vendor. It is defined in the document "TCG Vendor + Naming". + + The vendor specific area allows the TPM vendor to provide support for vendor options. The TPM + vendor may define the area to the TPM vendor's needs. +*/ + +typedef struct tdTPM_CAP_VERSION_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CAP_VERSION_INFO */ +#endif + TPM_VERSION version; /* The version and revision */ + uint16_t specLevel; /* A number indicating the level of ordinals supported */ + BYTE errataRev; /* A number indicating the errata version of the specification */ + BYTE tpmVendorID[4]; /* The vendor ID unique to each TPM manufacturer. */ + uint16_t vendorSpecificSize; /* The size of the vendor specific area */ + BYTE* vendorSpecific; /* Vendor specific information */ + /* NOTE Cannot be TPM_SIZED_BUFFER, because of uint16_t */ +} TPM_CAP_VERSION_INFO; + +/* 21.10 TPM_DA_ACTION_TYPE rev 100 + + This structure indicates the action taken when the dictionary attack mitigation logic is active, + when TPM_DA_STATE is TPM_DA_STATE_ACTIVE. +*/ + +typedef struct tdTPM_DA_ACTION_TYPE { + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_ACTION_TYPE */ + uint32_t actions; /* The action taken when TPM_DA_STATE is TPM_DA_STATE_ACTIVE. */ +} TPM_DA_ACTION_TYPE; + +/* 21.7 TPM_DA_INFO rev 100 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_DA_LOGIC request if + TPM_PERMANENT_FLAGS -> disableFullDALogicInfo is FALSE. + + It returns static information describing the TPM response to authorization failures that might + indicate a dictionary attack and dynamic information regarding the current state of the + dictionary attack mitigation logic. +*/ + +typedef struct tdTPM_DA_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_INFO */ +#endif + TPM_DA_STATE state; /* Dynamic. The actual state of the dictionary attack mitigation + logic. See 21.9. */ + uint16_t currentCount; /* Dynamic. The actual count of the authorization failure counter + for the selected entity type */ + uint16_t thresholdCount; /* Static. Dictionary attack mitigation threshold count for the + selected entity type */ + TPM_DA_ACTION_TYPE actionAtThreshold; /* Static Action of the TPM when currentCount passes + thresholdCount. See 21.10. */ + uint32_t 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. */ + TPM_SIZED_BUFFER vendorData; /* Vendor specific data field */ +} TPM_DA_INFO; + +/* 21.8 TPM_DA_INFO_LIMITED rev 100 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_DA_LOGIC request if + TPM_PERMANENT_FLAGS -> disableFullDALogicInfo is TRUE. + + It returns static information describing the TPM response to authorization failures that might + indicate a dictionary attack and dynamic information regarding the current state of the + dictionary attack mitigation logic. This structure omits information that might aid an attacker. +*/ + +typedef struct tdTPM_DA_INFO_LIMITED { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_INFO_LIMITED */ +#endif + TPM_DA_STATE state; /* Dynamic. The actual state of the dictionary attack mitigation + logic. See 21.9. */ + TPM_DA_ACTION_TYPE actionAtThreshold; /* Static Action of the TPM when currentCount passes + thresholdCount. See 21.10. */ + TPM_SIZED_BUFFER vendorData; /* Vendor specific data field */ +} TPM_DA_INFO_LIMITED; + +#endif + +/* Sanity check the size of the NV file vs. the maximum allocation size + + The multipliers are very conservative +*/ + +#if (TPM_ALLOC_MAX < \ + (4000 + \ + (TPM_OWNER_EVICT_KEY_HANDLES * 2000) + \ + TPM_MAX_NV_DEFINED_SPACE)) +#error "TPM_ALLOC_MAX too small for NV file size" +#endif + +/* Sanity check the size of the volatile file vs. the maximum allocation size + + The multipliers are very conservative +*/ + +#if (TPM_ALLOC_MAX < \ + (4000 + \ + TPM_KEY_HANDLES * 2000 + \ + TPM_MIN_TRANS_SESSIONS * 500 + \ + TPM_MIN_DAA_SESSIONS * 2000 + \ + TPM_MIN_AUTH_SESSIONS * 500)) +#error "TPM_ALLOC_MAX too small for volatile file size" +#endif diff --git a/src/tpm12/tpm_svnrevision.c b/src/tpm12/tpm_svnrevision.c new file mode 100644 index 0000000..e0bba60 --- /dev/null +++ b/src/tpm12/tpm_svnrevision.c @@ -0,0 +1 @@ +const unsigned short tpm_svn_revision = 4766; diff --git a/src/tpm12/tpm_svnrevision.h b/src/tpm12/tpm_svnrevision.h new file mode 100644 index 0000000..0ed4c4b --- /dev/null +++ b/src/tpm12/tpm_svnrevision.h @@ -0,0 +1,46 @@ +/********************************************************************************/ +/* */ +/* TPM svn revision */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_svnrevision.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_REVISION_H +#define TPM_REVISION_H + +extern const unsigned short tpm_svn_revision; + +#endif + diff --git a/src/tpm12/tpm_ticks.c b/src/tpm12/tpm_ticks.c new file mode 100644 index 0000000..c8dc58b --- /dev/null +++ b/src/tpm12/tpm_ticks.c @@ -0,0 +1,913 @@ +/********************************************************************************/ +/* */ +/* Tick Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ticks.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <string.h> +#include <stdio.h> + +#include "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_structures.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_time.h" + +#include "tpm_ticks.h" + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec); +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower); + +/* + UINT64 for currentTicks + + Internally, the UINT64 is stored as sec || usec. This makes calculations easy since TPM_GetTimeOfDay + returns those structure elements. + + The TPM_Uint64_Store() function, the public interface, converts this to a true 64 bit integer. +*/ + +/* TPM_Uint64_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Uint64_Init(TPM_UINT64 *tpm_uint64) +{ + printf(" TPM_Uint64_Init:\n"); + tpm_uint64->sec = 0; + tpm_uint64->usec = 0; + return; +} + +/* TPM_Uint64_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + This function does the conversion from a 64 bit usec to sec / usec. +*/ + +TPM_RESULT TPM_Uint64_Load(TPM_UINT64 *tpm_uint64, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Load:\n"); + /* load upper */ + if (rc == 0) { + rc = TPM_Load32(&upper, stream, stream_size); + } + /* load lower */ + if (rc == 0) { + rc = TPM_Load32(&lower, stream, stream_size); + } + /* convert from 64 bit usec to sec, usec */ + if (rc == 0) { + TPM_Uint64_ConvertTo(&(tpm_uint64->sec), + &(tpm_uint64->usec), + upper, + lower); + } + return rc; +} + +/* TPM_Uint64_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This function does the conversion from sec / usec to a 64 bit usec. +*/ + +TPM_RESULT TPM_Uint64_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_UINT64 *tpm_uint64) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Store:\n"); + /* store upper */ + if (rc == 0) { + /* convert to 64 bit number */ + TPM_Uint64_ConvertFrom(&upper, &lower, tpm_uint64->sec, tpm_uint64->usec); + rc = TPM_Sbuffer_Append32(sbuffer, upper); + } + /* store lower */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, lower); + } + return rc; +} + +void TPM_Uint64_Copy(TPM_UINT64 *dest, + const TPM_UINT64 *src) +{ + printf(" TPM_Uint64_Copy:\n"); + dest->sec = src->sec; + dest->usec = src->usec; + return; +} + +/* TPM_Uint64_ConvertFrom() does the calculation result = sec * 1000000 + usec and splits the result + into two uint32_t's. + + This may not be portable if the compiler does not support long long. +*/ + +/* TPM_Uint64_ConvertTo() does the calculation uint32_t || uint32_t to sec and usec. + + This may not be portable if the compiler does not support long long. +*/ + +#if defined(TPM_POSIX) || defined(TPM_SYSTEM_P) + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec) +{ + long long result; + + printf(" TPM_Uint64_ConvertFrom: sec %u, usec %u\n", sec, usec); + result = (sec * 1000000LL) + (long long)usec; + printf(" TPM_Uint64_ConvertFrom: Result usec %llu, %llx\n", result, result); + *upper = (result >> 32) & 0xffffffff; + *lower = result & 0xffffffff; + printf(" TPM_Uint64_ConvertFrom: Upper %u, %x\n", *upper, *upper); + printf(" TPM_Uint64_ConvertFrom: Lower %u, %x\n", *lower, *lower); + return; +} + +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower) +{ + long long result; + + printf(" TPM_Uint64_ConvertTo: Upper %u, %x\n", upper, upper); + printf(" TPM_Uint64_ConvertTo: Lower %u, %x\n", lower, lower); + result = ((long long)upper << 32) | (long long)lower; + printf(" TPM_Uint64_ConvertTo: Result usec %llu, %llx\n", result, result); + *sec = result / 1000000LL; + *usec = result % 1000000LL; + printf(" TPM_Uint64_ConvertTo: sec %u, usec %u\n", *sec, *usec); + return; +} + +#endif + + +TPM_RESULT TPM_Uint64_Test() +{ + TPM_RESULT rc = 0; + TPM_UINT64 uint64In; + TPM_UINT64 uint64Out; + TPM_STORE_BUFFER sbuffer; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Uint64_Test\n"); + TPM_Sbuffer_Init(&sbuffer); + uint64In.sec = 12345678; + uint64In.usec = 781234; + + if (rc == 0) { + rc = TPM_Uint64_Store(&sbuffer, &uint64In); + } + if (rc == 0) { + TPM_Sbuffer_Get(&sbuffer, (const unsigned char **)&stream, &stream_size); + rc = TPM_Uint64_Load(&uint64Out, &stream, &stream_size); + } + if (rc == 0) { + if ((uint64In.sec != uint64Out.sec) || + (uint64In.usec != uint64Out.usec)) { + printf("TPM_Uint64_Test: Error (fatal)\n"); + rc = TPM_FAILEDSELFTEST; + } + } + TPM_Sbuffer_Delete(&sbuffer); + return rc; +} + +/* + TPM_CURRENT_TICKS +*/ + +/* TPM_CurrentTicks_Init() initializes the tick structure + +*/ + +void TPM_CurrentTicks_Init(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + printf(" TPM_CurrentTicks_Init:\n"); + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + tpm_current_ticks->tickRate = TPM_TICK_RATE; + TPM_Nonce_Init(tpm_current_ticks->tickNonce); + TPM_Uint64_Init(&(tpm_current_ticks->initialTime)); + return; +} + +/* TPM_CurrentTicks_Start() sets the initialTime member to the + current time of day. + + It assumes TPM_CurrentTicks_Init() has been called +*/ + +TPM_RESULT TPM_CurrentTicks_Start(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Start:\n"); + if (rc == 0) { + /* current is relative to the initial value, and is always 0 */ + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + /* save the current time */ + rc = TPM_GetTimeOfDay(&(tpm_current_ticks->initialTime.sec), + &(tpm_current_ticks->initialTime.usec)); + } + if (rc == 0) { + tpm_current_ticks->tickRate = TPM_TICK_RATE; + rc = TPM_Nonce_Generate(tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_LoadAll() loads the standard TCG structure plus the SW TPM members + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CurrentTicks_Init() +*/ + +TPM_RESULT TPM_CurrentTicks_LoadAll(TPM_CURRENT_TICKS *tpm_current_ticks, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_LoadAll:\n"); + /* load tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CURRENT_TICKS, stream, stream_size); + } + /* load currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->currentTicks), stream, stream_size); + } + /* load tickRate */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_current_ticks->tickRate), stream, stream_size); + } + /* load tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_current_ticks->tickNonce, stream, stream_size); + } + /* load initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->initialTime), stream, stream_size); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CURRENT_TICKS); + } + /* store currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->currentTicks)); + } + /* store tickRate */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_current_ticks->tickRate); + } + /* store tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure plus the SW TPM members + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_StoreAll(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_StoreAll:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_CurrentTicks_Store(sbuffer, tpm_current_ticks); + } + /* store initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->initialTime)); + } + return rc; +} + +/* TPM_CurrentTicks_Update() updates the currentTicks member of TPM_CURRENT_TICKS + relative to the initial time + +*/ + +TPM_RESULT TPM_CurrentTicks_Update(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + uint32_t currentTimeSec; + uint32_t currentTimeUsec; + + printf(" TPM_CurrentTicks_Update: Initial %u sec %u usec\n", + tpm_current_ticks->initialTime.sec, tpm_current_ticks->initialTime.usec); + /* get the current time of day */ + if (rc == 0) { + rc = TPM_GetTimeOfDay(¤tTimeSec, ¤tTimeUsec); + } + /* Calculate: + currentTimeSec currentTimeUsec + - initialTimeSec initialTimeUsec + */ + if (rc == 0) { + /* case 1: no borrow */ + if (currentTimeUsec >= tpm_current_ticks->initialTime.usec) { + /* subtract usec */ + tpm_current_ticks->currentTicks.usec = currentTimeUsec - + tpm_current_ticks->initialTime.usec; + + /* check that time went forward */ + if (currentTimeSec >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + /* case 2: borrow */ + else { + /* subtract usec with borrow */ + tpm_current_ticks->currentTicks.usec = 1000000 + currentTimeUsec - + tpm_current_ticks->initialTime.usec; + /* check that time went forward, with borrow */ + if ((currentTimeSec - 1) >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - 1 - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + } + if (rc == 0) { + printf(" TPM_CurrentTicks_Update: Ticks %u sec %u usec\n", + tpm_current_ticks->currentTicks.sec, + tpm_current_ticks->currentTicks.usec); + } + return rc; +} + +/* TPM_CurrentTicks_Copy() copies the 'src' to 'dest' + +*/ + +void TPM_CurrentTicks_Copy(TPM_CURRENT_TICKS *dest, + TPM_CURRENT_TICKS *src) +{ + printf(" TPM_CurrentTicks_Copy:\n"); + TPM_Uint64_Copy(&(dest->currentTicks), &(src->currentTicks)); + dest->tickRate = src->tickRate; + TPM_Nonce_Copy(dest->tickNonce, src->tickNonce); + TPM_Uint64_Copy(&(dest->initialTime), &(src->initialTime)); + return; +} + +/* + Processing Functions +*/ + +/* 23. Timing Ticks rev 87 + + The TPM timing ticks are always available for use. The association of timing ticks to actual time + is a protocol that occurs outside of the TPM. See the design document for details. + + The setting of the clock type variable is a one time operation that allows the TPM to be + configured to the type of platform that is installed on. + + The ability for the TPM to continue to increment the timer ticks across power cycles of the + platform is a TPM and platform manufacturer decision. +*/ + +/* 23.1 TPM_GetTicks rev 87 + + This command returns the current tick count of the TPM. + + This command returns the current time held in the TPM. It is the responsibility of the external + system to maintain any relation between this time and a UTC value or local real time value. +*/ + +TPM_RESULT TPM_Process_GetTicks(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *t1CurrentTicks = NULL; /* The current time held in the TPM */ + + printf("TPM_Process_GetTicks: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetTicks: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. Set T1 to the internal TPM_CURRENT_TICKS structure */ + t1CurrentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(t1CurrentTicks); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetTicks: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Return T1 as currentTime. */ + returnCode = TPM_CurrentTicks_Store(response, t1CurrentTicks); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 23.2 TPM_TickStampBlob rev 101 + + This command applies a time stamp to the passed blob. The TPM makes no representation regarding + the blob merely that the blob was present at the TPM at the time indicated. + + The function performs a digital signature on the hash of digestToStamp and the current tick + count. + + It is the responsibility of the external system to maintain any relation between tick count and a + UTC value or local real time value. + +*/ + +TPM_RESULT TPM_Process_TickStampBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform digital + signatures. */ + TPM_NONCE antiReplay; /* Anti replay value added to signature */ + TPM_DIGEST digestToStamp; /* The digest to perform the tick stamp on */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle authorization + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_KEY *sigKey; /* signing key */ + TPM_SECRET *keyUsageAuth; + TPM_SECRET *hmacKey; + TPM_BOOL parentPCRStatus; + TPM_SIGN_INFO h1SignInfo; + TPM_STORE_BUFFER h2Data; + TPM_STORE_BUFFER h1sbuffer; /* serialization of h1SignInfo */ + TPM_DIGEST h3Digest; /* digest to be signed */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_TickStampBlob: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* freed @1 */ + TPM_SignInfo_Init(&h1SignInfo); /* freed @2 */ + TPM_Sbuffer_Init(&h2Data); /* freed @3 */ + TPM_Sbuffer_Init(&h1sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get digestToStamp parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TickStampBlob: antiReplay", antiReplay); + returnCode = TPM_Digest_Load(digestToStamp, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TickStampBlob: digestToStamp", digestToStamp); + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_TickStampBlob: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TickStampBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_TickStampBlob: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Checking key properties\n"); + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_IDENTITY) && + (sigKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_TickStampBlob: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_TickStampBlob: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + /* 4. If TPM_STCLEAR_DATA -> currentTicks is not properly initialized */ + /* a. Initialize the TPM_STCLEAR_DATA -> currentTicks */ + /* NOTE: Always initialized */ + /* 5. Create T1, a TPM_CURRENT_TICKS structure. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Creating TPM_CURRENT_TICKS structure\n"); + currentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ + printf("TPM_Process_TickStampBlob: Creating TPM_SIGN_INFO structure\n"); + /* NOTE: Done by TPM_SignInfo_Init() */ + /* a. Set H1 -> fixed to 'TSTP' */ + memcpy(h1SignInfo.fixed, "TSTP", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set H1 -> replay to antiReplay */ + TPM_Nonce_Copy(h1SignInfo.replay, antiReplay ); + /* c. Create H2 the concatenation of digestToStamp || T1 */ + /* add digestToStamp */ + returnCode = TPM_Digest_Store(&h2Data, digestToStamp); + } + /* add T1 (currentTicks) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(&h2Data, currentTicks); + } + /* d. Set H1 -> dataLen to the length of H2 */ + /* e. Set H1 -> data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(h1SignInfo.data), &h2Data); + } + /* 7. The TPM computes the signature, sig, using the key referenced by keyHandle, using SHA-1 of + H1 as the information to be signed */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Digesting TPM_SIGN_INFO structure\n"); + returnCode = TPM_SHA1_GenerateStructure(h3Digest, &h1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Signing TPM_SIGN_INFO digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h3Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TickStampBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 7. The TPM returns T1 as currentTicks parameter */ + returnCode = TPM_CurrentTicks_Store(response, currentTicks); + } + /* 6. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&sig); /* @1 */ + TPM_SignInfo_Delete(&h1SignInfo); /* @2 */ + TPM_Sbuffer_Delete(&h2Data); /* @3 */ + TPM_Sbuffer_Delete(&h1sbuffer); /* @4 */ + return rcf; +} + diff --git a/src/tpm12/tpm_ticks.h b/src/tpm12/tpm_ticks.h new file mode 100644 index 0000000..bebfdc6 --- /dev/null +++ b/src/tpm12/tpm_ticks.h @@ -0,0 +1,97 @@ +/********************************************************************************/ +/* */ +/* Tick Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ticks.h 4114 2010-09-30 22:24:32Z 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. */ +/********************************************************************************/ + +#ifndef TPM_TICKS_H +#define TPM_TICKS_H + +#include "tpm_types.h" +#include "tpm_global.h" +#include "tpm_structures.h" + +/* + UINT64 +*/ + +void TPM_Uint64_Init(TPM_UINT64 *tpm_uint64); +TPM_RESULT TPM_Uint64_Load(TPM_UINT64 *tpm_uint64, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Uint64_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_UINT64 *tpm_uint64); +void TPM_Uint64_Copy(TPM_UINT64 *dest, + const TPM_UINT64 *src); +TPM_RESULT TPM_Uint64_Test(void); + +/* + TPM_CURRENT_TICKS +*/ + +void TPM_CurrentTicks_Init(TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_LoadAll(TPM_CURRENT_TICKS *tpm_current_ticks, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CurrentTicks_StoreAll(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Start(TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Update(TPM_CURRENT_TICKS *tpm_current_ticks); +void TPM_CurrentTicks_Copy(TPM_CURRENT_TICKS *dest, + TPM_CURRENT_TICKS *src); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_GetTicks(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_TickStampBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm12/tpm_time.c b/src/tpm12/tpm_time.c new file mode 100644 index 0000000..3e747f6 --- /dev/null +++ b/src/tpm12/tpm_time.c @@ -0,0 +1,80 @@ +/********************************************************************************/ +/* */ +/* Time Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_time.c 4648 2011-10-25 19:22:18Z 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. */ +/********************************************************************************/ + +/* TPM_GetTimeOfDay() calls platform specific code to get the time in seconds and microseconds + */ + +#include <stdio.h> + +#include "tpm_debug.h" +#include "tpm_error.h" + +#include "tpm_time.h" + +/* TPM_GetTimeOfDay() gets the current time of day. + + Must return TPM_FAIL on error, so that the caller knows to shut down the TPM +*/ + +#ifdef TPM_POSIX + +#include <sys/time.h> + +TPM_RESULT TPM_GetTimeOfDay(uint32_t *tv_sec, uint32_t *tv_usec) +{ + TPM_RESULT rc = 0; + struct timeval tval; + int irc; + + irc = gettimeofday(&tval, NULL ); /* get the time */ + if (irc == 0) { + *tv_sec = tval.tv_sec; + *tv_usec = tval.tv_usec; + printf(" TPM_GetTimeOfDay: %d sec %d usec\n",*tv_sec, *tv_usec); + } + else { + printf("TPM_GetTimeOfDay: Error (fatal) getting time of day\n"); + rc = TPM_FAIL; + } + return rc; +} + +#endif + + diff --git a/src/tpm12/tpm_time.h b/src/tpm12/tpm_time.h new file mode 100644 index 0000000..d701551 --- /dev/null +++ b/src/tpm12/tpm_time.h @@ -0,0 +1,49 @@ +/********************************************************************************/ +/* */ +/* TPM Time Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_time.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_TIME_H +#define TPM_TIME_H + +#include "tpm_types.h" + +#define TPM_TICK_RATE 1 /* in usec for Linux */ +TPM_RESULT TPM_GetTimeOfDay(uint32_t *tv_sec, uint32_t *tv_usec); + + +#endif diff --git a/src/tpm12/tpm_transport.c b/src/tpm12/tpm_transport.c new file mode 100644 index 0000000..7b9c520 --- /dev/null +++ b/src/tpm12/tpm_transport.c @@ -0,0 +1,2935 @@ +/********************************************************************************/ +/* */ +/* Transport */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_transport.c 4719 2014-01-15 21:17:47Z 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 <stdlib.h> +#include <string.h> + +#include "tpm_audit.h" +#include "tpm_auth.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_process.h" +#include "tpm_secret.h" +#include "tpm_ticks.h" + +#include "tpm_transport.h" + +/* TPM_Transport_CryptMgf1() takes a 'src', a preallocated 'dest', and an MGF1 'pad' of length + 'len'. + + 'size is the total length of 'src' and 'dest'. + 'index' is the start of the encrypt area + 'len' is the length of the encrypt area + + It copies 'src' to 'dest' up to 'index'. + It then copies 'src' XOR'ed with 'pad' for 'len' + It then copies the remainder of 'src' to 'dest' +*/ + +TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest, + const unsigned char *src, + const unsigned char *pad, + uint32_t size, + uint32_t index, + uint32_t len) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Transport_CryptMgf1: size %u index %u len %u\n", size, index, len); + /* sanity check the length */ + if (rc == 0) { + if (index + len > size) { + printf("TPM_Transport_CryptMgf1: Error (fatal), bad size\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + /* leading clear text area */ + memcpy(dest, src, index); + dest += index; + src += index; + /* encrypt area */ + TPM_XOR(dest, pad, src, len); + dest += len; + src += len; + /* trailing clear text area */ + memcpy(dest, src, size - index - len); + } + return rc; +} + +/* TPM_Transport_CryptSymmetric() takes a 'src', a preallocated 'dest', and a 'symmetric_key' + 'pad_in' (CTR or IV) of length 'len'. + + 'size is the total length of 'src' and 'dest'. + 'index' is the start of the encrypt area + 'len' is the length of the encrypt area + + It copies 'src' to 'dest' up to 'index'. + It then encrypts 'src' to 'dest' using 'symmetric_key and 'pad_in' for 'len' + It then copies the remainder of 'src' to 'dest' +*/ + +TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest, + const unsigned char *src, + TPM_ALGORITHM_ID algId, /* algorithm */ + TPM_ENC_SCHEME encScheme, /* mode */ + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size, + uint32_t size, + uint32_t index, + uint32_t len) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Transport_CryptSymmetric: size %u index %u len %u\n", size, index, len); + /* sanity check the length */ + if (rc == 0) { + if (index + len > size) { + printf("TPM_Transport_CryptSymmetric: Error (fatal), bad size\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + /* leading clear text area */ + memcpy(dest, src, index); + dest += index; + src += index; + /* encrypt area */ + rc = TPM_SymmetricKeyData_StreamCrypt(dest, /* output */ + src, /* input */ + len, /* input */ + algId, /* algorithm */ + encScheme, /* mode */ + symmetric_key, /* input */ + symmetric_key_size, /* input */ + pad_in, /* input */ + pad_in_size); /* input */ + } + if (rc == 0) { + dest += len; + src += len; + /* trailing clear text area */ + memcpy(dest, src, size - index - len); + } + return rc; +} + +/* + Transport Sessions (the entire array) +*/ + +void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions) +{ + size_t i; + + printf(" TPM_TransportSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + TPM_TransportInternal_Init(&(transSessions[i])); + } + return; +} + +/* TPM_TransportSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportSessions_Init() + After use, call TPM_TransportSessions_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_TransportSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + if (rc == 0) { + if (activeCount > TPM_MIN_TRANS_SESSIONS) { + printf("TPM_TransportSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_TRANS_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_TransportSessions_Load: Loading %u sessions\n", activeCount); + } + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_TransportInternal_Load(&(transSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_TransportSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; /* free transport session slots */ + uint32_t activeCount; /* used transport session slots */ + + /* store active count */ + if (rc == 0) { + TPM_TransportSessions_GetSpace(&space, transSessions); + activeCount = TPM_MIN_TRANS_SESSIONS - space; + printf(" TPM_TransSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store transport sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { + if ((transSessions[i]).valid) { /* if the session is active */ + rc = TPM_TransportInternal_Store(sbuffer, &(transSessions[i])); + } + } + return rc; +} + +/* TPM_TransportSessions_Delete() terminates all sessions + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportSessions_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions) +{ + size_t i; + + printf(" TPM_TransportSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + TPM_TransportInternal_Delete(&(transSessions[i])); + } + return; +} + +/* TPM_TransportSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + printf(" TPM_TransportSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_TRANS_SESSIONS ; (*index)++) { + if (!((transSessions[*index]).valid)) { + printf(" TPM_TransportSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_TransportSessions_GetSpace() returns the number of unused transport sessions. + +*/ + +void TPM_TransportSessions_GetSpace(uint32_t *space, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + uint32_t i; + + printf(" TPM_TransportSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + if (!((transSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_TransportSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_TransportSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_TransportSessions_GetSpace(&space, transSessions); + /* store loaded handle count. Cast safe because of TPM_MIN_TRANS_SESSIONS value */ + printf(" TPM_TransportSessions_StoreHandles: %u handles\n", + TPM_MIN_TRANS_SESSIONS - space); + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_TRANS_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { + if ((transSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (transSessions[i]).transHandle); /* store it */ + } + } + return rc; +} + +/* TPM_TransportSessions_GetNewHandle() checks for space in the transport sessions table. + + If there is space, it returns a TPM_TRANSPORT_INTERNAL entry in 'tpm_transport_internal'. The + entry is marked 'valid'. + + Returns TPM_RESOURCES if there is no space in the transport sessions table. +*/ + +TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions) +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + TPM_TRANSHANDLE transportHandle = 0; /* no suggested value */ + + printf(" TPM_TransportSessions_GetNewHandle:\n"); + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_TransportSessions_IsSpace(&isSpace, &index, transportSessions); + if (!isSpace) { + printf("TPM_TransportSessions_GetNewHandle: Error, " + "no space in TransportSessions table\n"); + rc = TPM_RESOURCES; + } + } + /* assign transport handle */ + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(&transportHandle, /* I/O */ + transportSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_TransportSessions_GetNewHandle: Assigned handle %08x\n", transportHandle); + /* return the TPM_TRANSPORT_INTERNAL */ + *tpm_transport_internal = &(transportSessions[index]); + /* assign the handle */ + (*tpm_transport_internal)->transHandle = transportHandle; + (*tpm_transport_internal)->valid = TRUE; + } + return rc; +} + +/* TPM_TransportSessions_GetEntry() searches all 'transportSessions' entries for the entry matching + the handle, and returns the TPM_TRANSPORT_INTERNAL entry associated with the handle. + + Returns + 0 for success + TPM_INVALID_AUTHHANDLE if the handle is not found +*/ + +TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions, /* array */ + TPM_TRANSHANDLE transportHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_TransportSessions_GetEntry: transportHandle %08x\n", transportHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_TRANS_SESSIONS) && !found ; i++) { + if ((transportSessions[i].valid) && + (transportSessions[i].transHandle == transportHandle)) { /* found */ + found = TRUE; + *tpm_transport_internal = &(transportSessions[i]); + } + } + if (!found) { + printf(" TPM_TransportSessions_GetEntry: transport session handle %08x not found\n", + transportHandle); + rc = TPM_INVALID_AUTHHANDLE; + } + return rc; +} + +/* TPM_TransportSessions_AddEntry() adds an TPM_TRANSPORT_INTERNAL object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_TRANSPORT_INTERNAL *transSessions, /* input */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal) /* in */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_TransportSessions_AddEntry: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* check for valid TPM_TRANSPORT_INTERNAL */ + if (rc == 0) { + if (tpm_transport_internal == NULL) { /* NOTE: should never occur */ + printf("TPM_TransportSessions_AddEntry: Error (fatal), NULL TPM_TRANSPORT_INTERNAL\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_TransportSessions_IsSpace(&isSpace, &index, transSessions); + if (!isSpace) { + printf("TPM_TransportSessions_AddEntry: Error, transport session entries full\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + transSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); + } + if (rc == 0) { + tpm_transport_internal->transHandle = *tpm_handle; + tpm_transport_internal->valid = TRUE; + TPM_TransportInternal_Copy(&(transSessions[index]), tpm_transport_internal); + printf(" TPM_TransportSessions_AddEntry: Index %u handle %08x\n", + index, transSessions[index].transHandle); + } + return rc; +} + +/* TPM_TransportSessions_TerminateHandle() terminates the session associated with + 'transporthHandle'. + + If the session is exclusive (indicated by a match with TPM_STANY_FLAGS -> transportExclusive), + clear that flag. +*/ + +TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *transportSessions, + TPM_TRANSHANDLE transportHandle, + TPM_TRANSHANDLE *transportExclusive) +{ + TPM_RESULT rc = 0; + TPM_TRANSPORT_INTERNAL *tpm_transport_internal; + + printf(" TPM_TransportSessions_TerminateHandle: Handle %08x\n", transportHandle); + /* get the TPM_TRANSPORT_INTERNAL associated with the TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_TransportSessions_GetEntry(&tpm_transport_internal, + transportSessions, + transportHandle); + } + /* if the session being terminated is exclusive, reset the flag */ + if (rc == 0) { + if (transportHandle == *transportExclusive) { + printf(" TPM_TransportSessions_TerminateHandle: Is exclusive transport session\n"); + if (!(tpm_transport_internal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE)) { + printf("TPM_TransportSessions_TerminateHandle: Error (fatal), " + "attribute is not exclusive\n"); + rc = TPM_FAIL; /* internal error, should not occur */ + } + *transportExclusive = 0; + } + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_TransportInternal_Delete(tpm_transport_internal); + } + return rc; +} + +/* + TPM_TRANSPORT_PUBLIC +*/ + +/* TPM_TransportPublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + printf(" TPM_TransportPublic_Init:\n"); + tpm_transport_public->transAttributes = 0; + tpm_transport_public->algId = 0; + tpm_transport_public->encScheme = TPM_ES_NONE; + return; +} + +/* TPM_TransportPublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportPublic_Init() + After use, call TPM_TransportPublic_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_PUBLIC, stream, stream_size); + } + /* load transAttributes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_public->transAttributes ), stream, stream_size); + } + /* load algId */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_public->algId), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_transport_public->encScheme), stream, stream_size); + } + return rc; +} + +/* TPM_TransportPublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_PUBLIC); + } + /* store transAttributes */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->transAttributes); + } + /* store algId */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->algId); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_transport_public->encScheme); + } + return rc; +} + +/* TPM_TransportPublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportPublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + printf(" TPM_TransportPublic_Delete:\n"); + if (tpm_transport_public != NULL) { + TPM_TransportPublic_Init(tpm_transport_public); + } + return; +} + +/* TPM_TransportPublic_Copy() copies the 'src' to the 'dest' structure + +*/ + +TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest, + const TPM_TRANSPORT_PUBLIC *src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Copy:\n"); + /* copy transAttributes */ + dest->transAttributes = src->transAttributes; + /* copy algId */ + dest->algId = src->algId; + /* copy encScheme */ + dest->encScheme = src->encScheme; + return rc; +} + +/* TPM_TransportPublic_CheckAlgId() returns 'supported' TRUE if the transport encryption algorithm + is supported by the TPM + +*/ + +void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported, + TPM_ALGORITHM_ID algId) +{ + printf(" TPM_TransportPublic_CheckAlgId: %08x\n", algId); + switch (algId) { + /* supported protocols */ + case TPM_ALG_MGF1: + case TPM_ALG_AES128: + *supported = TRUE; + break; + /* unsupported protocols */ + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + *supported = FALSE; + break; + } + return; +} + +/* TPM_TransportPublic_CheckEncScheme() returns success and the blockSize if the transport algId and + encScheme are supported by the TPM. +*/ + +TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_CheckEncScheme: algId %08x encScheme %04hx\n", algId, encScheme); + switch (algId) { + /* supported protocols with no encScheme */ + case TPM_ALG_MGF1: + *blockSize = 0; /* MGF1 does not use blocks */ + if (FIPS) { + printf("TPM_TransportPublic_CheckEncScheme: Error, " + "TPM_ALG_MGF1 not supported in FIPS\n"); + rc = TPM_INAPPROPRIATE_ENC; + } + /* For TPM_ALG_MGF1, TPM_ENC_SCHEME is not used. The TPM MAY validate that TPM_ENC_SCHEME + is TPM_ES_NONE. */ + if (encScheme != TPM_ES_NONE) { + printf("TPM_TransportPublic_CheckEncScheme: Error, " + "TPM_ALG_MGF1 must use TPM_ES_NONE\n"); + rc = TPM_INAPPROPRIATE_ENC; + } + break; + /* protocols with encScheme */ + case TPM_ALG_AES128: + switch(encScheme) { + case TPM_ES_SYM_CTR: /* CTR mode */ + case TPM_ES_SYM_OFB: /* OFB mode */ + *blockSize = 128/8; + break; + default: + printf("TPM_TransportPublic_CheckEncScheme: Error, AES128 encScheme not supported\n"); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + break; + /* unsupported protocols */ + case TPM_ALG_AES192: + case TPM_ALG_AES256: + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_XOR: + default: + printf("TPM_TransportPublic_CheckEncScheme: Error, algId not supported\n"); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + return rc; +} + +/* + TPM_TRANSPORT_INTERNAL +*/ + +/* TPM_TransportInternal_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + printf(" TPM_TransportInternal_Init:\n"); + TPM_Secret_Init(tpm_transport_internal->authData); + TPM_TransportPublic_Init(&(tpm_transport_internal->transPublic)); + tpm_transport_internal->transHandle = 0; + TPM_Nonce_Init(tpm_transport_internal->transNonceEven); + TPM_Digest_Init(tpm_transport_internal->transDigest); + tpm_transport_internal->valid = FALSE; + return; +} + +/* TPM_TransportInternal_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportInternal_Init() + After use, call TPM_TransportInternal_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportInternal_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_INTERNAL, stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_transport_internal->authData, stream, stream_size); + } + /* load transPublic */ + if (rc == 0) { + rc = TPM_TransportPublic_Load(&(tpm_transport_internal->transPublic), stream, stream_size); + } + /* load transHandle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_internal->transHandle), stream, stream_size); + } + /* load transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_transport_internal->transNonceEven, stream, stream_size); + } + /* load transDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_transport_internal->transDigest, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + tpm_transport_internal->valid = TRUE; + } + return rc; +} + +/* TPM_TransportInternal_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportInternal_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_INTERNAL); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_transport_internal->authData); + } + /* store transPublic */ + if (rc == 0) { + rc = TPM_TransportPublic_Store(sbuffer, &(tpm_transport_internal->transPublic)); + } + /* store transHandle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_internal->transHandle); + } + /* store transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_transport_internal->transNonceEven); + } + /* store transDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_internal->transDigest); + } + return rc; +} + +/* TPM_TransportInternal_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportInternal_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + printf(" TPM_TransportInternal_Delete:\n"); + if (tpm_transport_internal != NULL) { + TPM_TransportPublic_Delete(&(tpm_transport_internal->transPublic)); + TPM_TransportInternal_Init(tpm_transport_internal); + } + return; +} + +/* TPM_TransportInternal_Copy() copies the source to the destination. + +*/ + +void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal, + TPM_TRANSPORT_INTERNAL *src_transport_internal) +{ + TPM_Secret_Copy(dest_transport_internal->authData, src_transport_internal->authData); + TPM_TransportPublic_Copy(&(dest_transport_internal->transPublic), + &(src_transport_internal->transPublic)); + dest_transport_internal->transHandle = src_transport_internal->transHandle; + TPM_Nonce_Copy(dest_transport_internal->transNonceEven, src_transport_internal->transNonceEven); + TPM_Digest_Copy(dest_transport_internal->transDigest, src_transport_internal->transDigest); + dest_transport_internal->valid = src_transport_internal->valid; +} + +/* TPM_TransportInternal_Check() checks the authorization of a command. + + There is no need to protect against dictionary attacks. The first failure terminates the + transport session. + + Returns TPM_AUTH2FAIL if the TPM_AUTHDATA does not match. +*/ + +TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, /* digest of inputs + above line */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_NONCE transNonceOdd, /* Nonce generated + by system + associated with + transHandle */ + TPM_BOOL continueTransSession, + TPM_AUTHDATA transAuth) /* Authorization + digest for + input */ +{ + TPM_RESULT rc = 0; + TPM_BOOL valid; + + printf(" TPM_TransportInternal_Check:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_TransportInternal_Check: inParamDigest", inParamDigest); + TPM_PrintFour(" TPM_TransportInternal_Check: usageAuth (key)", + tpm_transport_internal->authData); + TPM_PrintFour(" TPM_TransportInternal_Check: nonceEven", + tpm_transport_internal->transNonceEven); + TPM_PrintFour(" TPM_TransportInternal_Check: nonceOdd", transNonceOdd); + printf (" TPM_TransportInternal_Check: continueSession %02x\n", continueTransSession); + /* HMAC the inParamDigest, transLastNonceEven, transNonceOdd, continueTransSession */ + /* transLastNonceEven is retrieved from internal transport session storage */ + rc = TPM_HMAC_Check(&valid, + transAuth, /* expected, from command */ + tpm_transport_internal->authData, /* key */ + sizeof(TPM_DIGEST), inParamDigest, /* command digest */ + sizeof(TPM_NONCE), tpm_transport_internal->transNonceEven, /* 2H */ + sizeof(TPM_NONCE), transNonceOdd, /* 3H */ + sizeof(TPM_BOOL), &continueTransSession, /* 4H */ + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_TransportInternal_Check: Error, authorization failed\n"); + rc = TPM_AUTH2FAIL; + } + } + return rc; +} + +/* TPM_TransportInternal_Set() sets the transport response transAuth. + + It conditionally generates the next transNonceEven. + + It appends transNonceEven and continueTransSession to the response. + + It generates transAuth using outParamDigest and the standard 'below the line' HMAC rules and + appends it to the response. +*/ + +TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_DIGEST outParamDigest, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_BOOL generateNonceEven) +{ + TPM_RESULT rc = 0; + TPM_AUTHDATA transAuth; /* The authorization digest for the returned parameters */ + + printf(" TPM_TransportInternal_Set:\n"); + /* generate transNonceEven if not already done by caller */ + if ((rc == 0) && generateNonceEven) { + rc = TPM_Nonce_Generate(tpm_transport_internal->transNonceEven); + } + /* append transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(response, tpm_transport_internal->transNonceEven); + } + /* append continueTransSession*/ + if (rc == 0) { + rc = TPM_Sbuffer_Append(response, &continueTransSession, sizeof(TPM_BOOL)); + } + /* Calculate transAuth using the transport session authData */ + if (rc == 0) { + rc = TPM_Authdata_Generate(transAuth, /* result */ + tpm_transport_internal->authData, /* HMAC key */ + outParamDigest, /* params */ + tpm_transport_internal->transNonceEven, + transNonceOdd, + continueTransSession); + } + /* append transAuth */ + if (rc == 0) { + rc = TPM_Authdata_Store(response, transAuth); + } + return rc; +} + +/* + TPM_TRANSPORT_LOG_IN +*/ + +/* TPM_TransportLogIn_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + printf(" TPM_TransportLogIn_Init:\n"); + TPM_Digest_Init(tpm_transport_log_in->parameters); + TPM_Digest_Init(tpm_transport_log_in->pubKeyHash); + return; +} + +/* TPM_TransportLogIn_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportLogIn_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_IN); + } + /* store parameters */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->parameters); + } + /* store pubKeyHash */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->pubKeyHash); + } + return rc; +} + +/* TPM_TransportLogIn_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportLogIn_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + printf(" TPM_TransportLogIn_Delete:\n"); + if (tpm_transport_log_in != NULL) { + TPM_TransportLogIn_Init(tpm_transport_log_in); + } + return; +} + +/* TPM_TransportLogIn_Extend() extends 'tpm_digest' + + tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_in) +*/ + +TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_TransportLogIn_Extend:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize TPM_TRANSPORT_LOG_IN */ + if (rc == 0) { + rc = TPM_TransportLogIn_Store(&sbuffer, tpm_transport_log_in); + } + if (rc == 0) { + /* get the TPM_TRANSPORT_LOG_IN serialization results */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); + TPM_PrintAll(" TPM_TransportLogIn_Extend", buffer, length); + rc = TPM_SHA1(tpm_digest, + TPM_DIGEST_SIZE, tpm_digest, + length, buffer, + 0, NULL); + TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_TRANSPORT_LOG_OUT +*/ + +/* TPM_TransportLogOut_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + printf(" TPM_TransportLogOut_Init:\n"); + TPM_CurrentTicks_Init(&(tpm_transport_log_out->currentTicks)); + TPM_Digest_Init(tpm_transport_log_out->parameters); + tpm_transport_log_out = 0; + return; +} + +/* TPM_TransportLogOut_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportLogOut_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_OUT); + } + /* store currentTicks */ + if (rc == 0) { + rc = TPM_CurrentTicks_Store(sbuffer, &(tpm_transport_log_out->currentTicks)); + } + /* store parameters */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_out->parameters); + } + /* store locality */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_log_out->locality); + } + return rc; +} + +/* TPM_TransportLogOut_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportLogOut_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + printf(" TPM_TransportLogOut_Delete:\n"); + if (tpm_transport_log_out != NULL) { + TPM_TransportLogOut_Init(tpm_transport_log_out); + } + return; +} + +/* TPM_TransportLogOut_Extend() extends 'tpm_digest' + + tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_out) +*/ + +TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_TransportLogOut_Extend:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize TPM_TRANSPORT_LOG_OUT */ + if (rc == 0) { + rc = TPM_TransportLogOut_Store(&sbuffer, tpm_transport_log_out); + } + if (rc == 0) { + /* get the TPM_TRANSPORT_LOG_OUT serialization results */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); + TPM_PrintAll(" TPM_TransportLogOut_Extend:", buffer, length); + rc = TPM_SHA1(tpm_digest, + TPM_DIGEST_SIZE, tpm_digest, + length, buffer, + 0, NULL); + TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_TRANSPORT_AUTH +*/ + +/* TPM_TransportAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + printf(" TPM_TransportAuth_Init:\n"); + TPM_Secret_Init(tpm_transport_auth->authData); + return; +} + +/* TPM_TransportAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportAuth_Init() + After use, call TPM_TransportAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportAuth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_AUTH, stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_transport_auth->authData, stream, stream_size); + } + return rc; +} + +/* TPM_TransportAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportAuth_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_AUTH); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_transport_auth->authData); + } + return rc; +} + +/* TPM_TransportAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + printf(" TPM_TransportAuth_Delete:\n"); + if (tpm_transport_auth != NULL) { + TPM_TransportAuth_Init(tpm_transport_auth); + } + return; +} + +/* TPM_TransportAuth_DecryptSecret() decrypts the secret using the private key. The + result is deserialized and stored in the TPM_TRANSPORT_AUTH structure. +*/ + +TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, /* result */ + TPM_SIZED_BUFFER *secret, /* encrypted input */ + TPM_KEY *tpm_key) /* key for decrypting */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_TransportAuth_DecryptSecret:\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted data */ + secret->buffer, /* encrypted data */ + secret->size, /* encrypted data size */ + tpm_key); + } + /* load the TPM_TRANSPORT_AUTH structure from the decrypted data stream */ + if (rc == 0) { + /* use temporary variables, because TPM_TransportAuth_Load() moves the stream */ + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_TransportAuth_Load(tpm_transport_auth, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + +/* + Processing Functions +*/ + +/* 24.1 TPM_EstablishTransport rev 98 + + This establishes the transport session. Depending on the attributes specified for the session + this may establish shared secrets, encryption keys, and session logs. The session will be in use + for by the TPM_ExecuteTransport command. + + The only restriction on what can happen inside of a transport session is that there is no + "nesting" of sessions. It is permissible to perform operations that delete internal state and + make the TPM inoperable. +*/ + +TPM_RESULT TPM_Process_EstablishTransport(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 encHandle; /* The handle to the key that encrypted the blob */ + TPM_TRANSPORT_PUBLIC transPublic; /* The public information describing the transport + session */ + TPM_SIZED_BUFFER secret; /* The encrypted secret area */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for + keyHandle authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: encKey.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 dataAuthHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *encKey = NULL; /* the key specified by encHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *encKeyUsageAuth; + TPM_AUTHDATA *a1AuthData = NULL; + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; + TPM_TRANSPORT_AUTH k1TransportAuth; + uint32_t blockSize; /* symmetric key block size, not used */ + TPM_TRANSPORT_LOG_IN l1TransportLogIn; + TPM_TRANSPORT_LOG_OUT l2TransportLogOut; + TPM_STORE_BUFFER transPublicSbuffer; /* serialized transPublic */ + const unsigned char *transPublicBuffer; /* serialized buffer */ + uint32_t transPublicLength; /* serialization length */ + TPM_STORE_BUFFER currentTicksSbuffer; /* serialized currentTicks */ + const unsigned char *currentTicksBuffer; /* serialized buffer */ + uint32_t currentTicksLength; /* serialization length */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ + uint32_t nSecretSize; /* secretSize in nbo */ + TPM_RESULT nReturnCode; /* returnCode in nbo */ + TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ + TPM_BOOL trans_session_added = FALSE; + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS currentTicks; /* The current tick count */ + TPM_NONCE transNonceEven; /* The even nonce in use for subsequent + execute transport */ + + printf("TPM_Process_EstablishTransport: Ordinal Entry\n"); + TPM_TransportPublic_Init(&transPublic); /* freed @1 */ + TPM_SizedBuffer_Init(&secret); /* freed @2 */ + TPM_CurrentTicks_Init(¤tTicks); /* no need to free */ + TPM_TransportAuth_Init(&k1TransportAuth); /* freed @4 */ + TPM_TransportLogIn_Init(&l1TransportLogIn); /* freed @5 */ + TPM_TransportLogOut_Init(&l2TransportLogOut); /* freed @6 */ + TPM_Sbuffer_Init(&transPublicSbuffer); /* freed @7 */ + TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ + /* + get inputs + */ + /* get encHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&encHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get transPublic */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: keyHandle %08x\n", encHandle); + returnCode = TPM_TransportPublic_Load(&transPublic, &command, ¶mSize); + } + /* get secret */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: transPublic->transAttributes %08x\n", + transPublic.transAttributes); + returnCode = TPM_SizedBuffer_Load(&secret, &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, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_EstablishTransport: 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 + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If encHandle is TPM_KH_TRANSPORT then */ + if (encHandle == TPM_KH_TRANSPORT) { + printf("TPM_Process_EstablishTransport: TPM_KH_TRANSPORT clear text secret\n"); + /* a. If tag is NOT TPM_TAG_RQU_COMMAND return TPM_BADTAG */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_COMMAND) { + printf("TPM_Process_EstablishTransport: Error, " + "TPM_KH_TRANSPORT but not auth-0\n"); + returnCode = TPM_BADTAG; + } + } + /* b. If transPublic -> transAttributes specifies TPM_TRANSPORT_ENCRYPT return + TPM_BAD_SCHEME */ + if (returnCode == TPM_SUCCESS) { + if (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) { + printf("TPM_Process_EstablishTransport: Error, " + "TPM_KH_TRANSPORT but TPM_TRANSPORT_ENCRYPT\n"); + returnCode = TPM_BAD_SCHEME; + } + } + /* c. If secretSize is not 20 return TPM_BAD_PARAM_SIZE */ + if (returnCode == TPM_SUCCESS) { + if (secret.size != TPM_DIGEST_SIZE) { + printf("TPM_Process_EstablishTransport: Error, secretSize %u not %u\n", + secret.size, TPM_DIGEST_SIZE); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* d. Set A1 to secret */ + if (returnCode == TPM_SUCCESS) { + a1AuthData = (TPM_AUTHDATA *)(secret.buffer); + TPM_PrintFour("TPM_Process_EstablishTransport: transport clear text authData", *a1AuthData); + } + } + /* 2. Else */ + else { + printf("TPM_Process_EstablishTransport: Decrypt secret\n"); + /* get the key corresponding to the encHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&encKey, &parentPCRStatus, tpm_state, + encHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* a. encHandle -> keyUsage MUST be TPM_KEY_STORAGE or TPM_KEY_LEGACY return + TPM_INVALID_KEYUSAGE on error */ + if (returnCode == TPM_SUCCESS) { + if ((encKey->keyUsage != TPM_KEY_STORAGE) && + (encKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_EstablishTransport: Error, " + "key keyUsage %04hx must be TPM_KEY_STORAGE or TPM_KEY_LEGACY\n", + encKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If encHandle -> authDataUsage does not equal TPM_AUTH_NEVER and tag is NOT + TPM_TAG_RQU_AUTH1_COMMAND return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + if (encKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_EstablishTransport: Error, " + "encKey authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get encHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&encKeyUsageAuth, encKey); + } + /* 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, + encKey, + encKeyUsageAuth, /* OIAP */ + encKey->tpm_store_asymkey-> + pubDataDigest); /*OSAP */ + } + /* c. Using encHandle -> usageAuth, validate the AuthData to use the key and the + parameters to the command */ + 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, + keyAuth); /* Authorization digest for input */ + } + /* d. Create K1 a TPM_TRANSPORT_AUTH structure by decrypting secret using the key + pointed to by encHandle */ + /* e. Validate K1 for tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportAuth_DecryptSecret(&k1TransportAuth, + &secret, + encKey); + + } + /* f. Set A1 to K1 -> authData */ + if (returnCode == TPM_SUCCESS) { + a1AuthData = &(k1TransportAuth.authData); + TPM_PrintFour("TPM_Process_EstablishTransport: transport decrypted authData", + *a1AuthData); + } + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_EstablishTransport: transport authData", *a1AuthData); + } + /* 3. If transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT */ + if ((returnCode == TPM_SUCCESS) && (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT)) { + printf("TPM_Process_EstablishTransport: Check encrypt attributes\n"); + /* a. If TPM_PERMANENT_FLAGS -> FIPS is true and transPublic -> algId is equal to + TPM_ALG_MGF1 return TPM_INAPPROPRIATE_ENC */ + /* b. Check if the transPublic -> algId is supported, if not return TPM_BAD_KEY_PROPERTY */ + /* c. If transPublic -> algid is TPM_ALG_AESXXX, check that transPublic -> encScheme is + supported, if not return TPM_INAPPROPRIATE_ENC */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize, + transPublic.algId, + transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* d. Perform any initializations necessary for the algorithm */ + } + /* 4. Generate transNonceEven from the TPM RNG */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Generate(transNonceEven); + } + /* 5. Create T1 a TPM_TRANSPORT_INTERNAL structure */ + /* NOTE Done by TPM_TransportInternal_Init() */ + /* a. Ensure that the TPM has sufficient internal space to allocate the transport session, + return TPM_RESOURCES on error */ + /* b. Assign a T1 -> transHandle value. This value is assigned by the TPM */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_INTERNAL\n"); + returnCode = + TPM_TransportSessions_GetNewHandle(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions); + } + if (returnCode == TPM_SUCCESS) { + /* record that the entry is allocated, for invalidation on error */ + trans_session_added = TRUE; + /* c. Set T1 -> transDigest to NULL */ + TPM_Digest_Init(t1TpmTransportInternal->transDigest); + /* d. Set T1 -> transPublic to transPublic */ + TPM_TransportPublic_Copy(&(t1TpmTransportInternal->transPublic), &transPublic); + /* e. Set T1-> transNonceEven to transNonceEven */ + TPM_Nonce_Copy(t1TpmTransportInternal->transNonceEven , transNonceEven); + /* f. Set T1 -> authData to A1 */ + TPM_Secret_Copy(t1TpmTransportInternal->authData, *a1AuthData); + /* 6. If TPM_STANY_DATA -> currentTicks is not properly initialized */ + /* a. Initialize the TPM_STANY_DATA -> currentTicks */ + returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); + } + /* 7. Set currentTicks to TPM_STANY_DATA -> currentTicks */ + if (returnCode == TPM_SUCCESS) { + TPM_CurrentTicks_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks)); + } + /* 8. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_IN\n"); + /* a. Create L1 a TPM_TRANSPORT_LOG_IN structure */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* i. Set L1 -> parameters to SHA-1 (ordinal || transPublic || secretSize || secret) */ + /* serialize transPublic */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportPublic_Store(&transPublicSbuffer, &transPublic); + } + if (returnCode == TPM_SUCCESS) { + /* get the transPublic serialization results */ + TPM_Sbuffer_Get(&transPublicSbuffer, &transPublicBuffer, &transPublicLength); + /* digest the fields */ + nOrdinal = htonl(ordinal); + nSecretSize = htonl(secret.size); + returnCode = TPM_SHA1(l1TransportLogIn.parameters, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + transPublicLength, transPublicBuffer, + sizeof(uint32_t), &nSecretSize, + secret.size, secret.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set L1 -> pubKeyHash to NULL */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* iii. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L1) */ + printf("TPM_Process_EstablishTransport: Extend transDigest with input\n"); + returnCode = TPM_TransportLogIn_Extend(t1TpmTransportInternal->transDigest, + &l1TransportLogIn); + } + /* b. Create L2 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* i. Set L2 -> parameters to SHA-1 (returnCode || ordinal || locality || currentTicks || + transNonceEven) */ + /* serialize currentTicks */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_OUT\n"); + returnCode = TPM_CurrentTicks_Store(¤tTicksSbuffer, ¤tTicks); + } + if (returnCode == TPM_SUCCESS) { + /* get the currentTicks serialization results */ + TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); + nReturnCode = htonl(returnCode); + nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); + returnCode = TPM_SHA1(l2TransportLogOut.parameters, + sizeof(TPM_RESULT), &nReturnCode, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + sizeof(TPM_MODIFIER_INDICATOR), &nLocality, + currentTicksLength, currentTicksBuffer, + TPM_NONCE_SIZE, transNonceEven, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set L2 -> locality to the locality of this command */ + l2TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* iii. Set L2 -> currentTicks to currentTicks, this MUST be the same value that is + returned in the currentTicks parameter */ + TPM_CurrentTicks_Copy(&(l2TransportLogOut.currentTicks), ¤tTicks); + /* iv. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L2) */ + printf("TPM_Process_EstablishTransport: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, + &l2TransportLogOut); + } + } + /* 9. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_EXCLUSIVE then + set TPM_STANY_FLAGS -> transportExclusive to TRUE */ + if (returnCode == TPM_SUCCESS) { + if (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE) { + printf("TPM_Process_EstablishTransport: Session is exclusive\n"); + tpm_state->tpm_stany_flags.transportExclusive = t1TpmTransportInternal->transHandle; + } + } + /* a. Execution of any command other than TPM_ExecuteTransport or TPM_ReleaseTransportSigned + targeting this transport session will cause the abnormal invalidation of this transport + session transHandle */ + /* b. The TPM gives no indication, other than invalidation of transHandle, that the session is + terminated */ + /* NOTE Done by TPM_Process_Preprocess() */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_EstablishTransport: 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) { + /* 10. Return T1 -> transHandle as transHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, t1TpmTransportInternal->transHandle); + } + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return locality */ + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(response, ¤tTicks); + } + if (returnCode == TPM_SUCCESS) { + /* return transNonceEven */ + returnCode = TPM_Nonce_Store(response, transNonceEven); + /* 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); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING))) && + trans_session_added) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + t1TpmTransportInternal->transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* + cleanup + */ + TPM_TransportPublic_Delete(&transPublic); /* @1 */ + TPM_SizedBuffer_Delete(&secret); /* @2 */ + TPM_TransportAuth_Delete(&k1TransportAuth); /* @4 */ + TPM_TransportLogIn_Delete(&l1TransportLogIn); /* @5 */ + TPM_TransportLogOut_Delete(&l2TransportLogOut); /* @6 */ + TPM_Sbuffer_Delete(&transPublicSbuffer); /* @7 */ + TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ + return rcf; +} + +/* 24.2 TPM_ExecuteTransport rev 117 + + Delivers a wrapped TPM command to the TPM where the TPM unwraps the command and then executes the + command. + + TPM_ExecuteTransport uses the same rolling nonce paradigm as other authorized TPM commands. The + even nonces start in EstablishTransport and change on each invocation of TPM_ExecuteTransport. + + The only restriction on what can happen inside of a transport session is that there is no + "nesting" of sessions. It is permissible to perform operations that delete internal state and + make the TPM inoperable. + + Because, in general, key handles are not logged, a digest of the corresponding public key is + logged. In cases where the key handle is logged (e.g. TPM_OwnerReadInternalPub), the + public key is also logged. + + The wrapped command is audited twice - once according to the actions of TPM_ExecuteTransport and + once within the wrapped command itself according to the special rules for auditing a command + wrapped in an encrypted transport session. +*/ + +TPM_RESULT TPM_Process_ExecuteTransport(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_SIZED_BUFFER wrappedCmd; /* The wrapped command */ + TPM_TRANSHANDLE transHandle; /* The transport session handle */ + TPM_NONCE transNonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueTransSession; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA transAuth; /* HMAC for transHandle key: transHandle -> + authData */ + + /* processing parameters */ + /* unsigned char * inParamStart; /\* starting point of inParam's *\/ */ + /* unsigned char * inParamEnd; /\* ending point of inParam's *\/ */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transHandleValid = FALSE; + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; + TPM_TRANSPORT_INTERNAL t1TransportCopy; /* because original might be invalidated */ + TPM_BOOL transportWrappable; /* inner command can be wrapped in + transport */ + uint32_t keyHandles; /* number of key handles in ordw */ + uint32_t keyHandle1Index; /* index of key handles in wrapped command */ + uint32_t keyHandle2Index; + TPM_KEY_HANDLE keyHandle1; /* key handles in wrapped command */ + TPM_KEY_HANDLE keyHandle2; + uint32_t blockSize; /* symmetric key block size, if needed */ + TPM_RESOURCE_TYPE wrappedResourceType; /* for key handle special cases */ + TPM_COMMAND_CODE ordw; /* wrapped ORDW */ + uint32_t e1Dataw; /* index into wrapped E1 */ + uint32_t len1; /* wrapped LEN1 */ + unsigned char *g1Mgf1; /* input MGF1 XOR string */ + unsigned char *g2Mgf1; /* output MGF1 XOR string */ + unsigned char *decryptCmd; /* decrypted wrapped command */ + unsigned char *cmdStream; /* temporary for constructing decryptCmd */ + uint32_t cmdStreamSize; + TPM_COMMAND_CODE nOrdw; /* ordinal in nbo */ + TPM_COMMAND_CODE nOrdet; /* ordinal in nbo */ + uint32_t nWrappedCmdSize; /* wrappedCmdSize in nbo */ + TPM_DIGEST h1InWrappedDigest; + TPM_DIGEST h2OutWrappedDigest; + TPM_TRANSPORT_LOG_IN l2TransportLogIn; + TPM_TRANSPORT_LOG_OUT l3TransportLogOut; + TPM_DIGEST k2PubkeyDigest; + TPM_DIGEST k3PubkeyDigest; + TPM_KEY *k2Key; /* wrapped command keys */ + TPM_KEY *k3Key; + TPM_BOOL parentPCRStatus; + TPM_STORE_BUFFER wrappedRspSbuffer; + const unsigned char *wrappedRspStream; + uint32_t wrappedRspStreamSize; + uint32_t s2Dataw; /* index into S2 */ + uint32_t len2; /* length of S2 */ + TPM_RESULT rcw; /* wrapped return code */ + TPM_RESULT nRcw; /* return code in nbo */ + TPM_STORE_BUFFER currentTicksSbuffer; + const unsigned char *currentTicksBuffer; /* serialized buffer */ + uint32_t currentTicksLength; /* serialization length */ + TPM_RESULT nRCet; /* return code in nbo */ + TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ + uint32_t nWrappedRspStreamSize; /* wrappedRspStreamSize in nbo */ + unsigned char *encryptRsp; /* encrypted response */ + + /* output parameters */ + TPM_DIGEST outParamDigest; + TPM_UINT64 currentTicks; /* The current ticks when the command was + executed */ + TPM_SIZED_BUFFER wrappedRsp; /* The wrapped response */ + + printf("TPM_Process_ExecuteTransport: Ordinal Entry\n"); + transportInternal = transportInternal; /* TPM_ExecuteTransport cannot be wrapped */ + TPM_SizedBuffer_Init(&wrappedCmd); /* freed @1 */ + TPM_SizedBuffer_Init(&wrappedRsp); /* freed @2 */ + g1Mgf1 = NULL; /* freed @3 */ + decryptCmd = NULL; /* freed @4 */ + TPM_TransportLogIn_Init(&l2TransportLogIn); /* freed @5 */ + TPM_TransportLogOut_Init(&l3TransportLogOut); /* freed @6 */ + TPM_Sbuffer_Init(&wrappedRspSbuffer); /* freed @7 */ + TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ + g2Mgf1 = NULL; /* freed @9 */ + TPM_TransportInternal_Init(&t1TransportCopy); /* freed @10 */ + encryptRsp = NULL; /* freed @11 */ + /* + get inputs + */ + if (returnCode == TPM_SUCCESS) { + /* save the starting point of inParam's for authorization and auditing */ + /* inParamStart = command; */ + /* get wrappedCmd */ + returnCode = TPM_SizedBuffer_Load(&wrappedCmd, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: wrapped command size %u\n", wrappedCmd.size); + /* save the ending point of inParam's for authorization and auditing */ + /* inParamEnd = command; */ + /* NOTE: The common TPM_GetInParamDigest() is not called here, since inParamDigest cannot be + calculated until the wrapped command is decrypted */ + returnCode = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + ordinal, + &(tpm_state->tpm_permanent_data)); + } + /* 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(&transHandle, + &transHandleValid, + transNonceOdd, + &continueTransSession, + transAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: transHandle %08x\n", transHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ExecuteTransport: 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) { + transHandleValid = FALSE; + } + /* + Processing + */ + /* if there is an active exclusive transport session and it's not this session, terminate it */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && + (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { + returnCode = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions, + transHandle); + } + /* For the corner case where the wrapped command invalidates the transport session, make a copy + for the response. */ + if (returnCode == TPM_SUCCESS) { + TPM_TransportInternal_Copy(&t1TransportCopy, + t1TpmTransportInternal); + } + /* 2. Parse wrappedCmd */ + /* a. Set TAGw, LENw, and ORDw to the parameters from wrappedCmd */ + /* b. Set E1 to DATAw */ + /* i. This pointer is ordinal dependent and requires the execute transport command to parse + wrappedCmd */ + /* c. Set LEN1 to the length of DATAw */ + /* i. DATAw always ends at the start of AUTH1w if AUTH1w is present */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OrdinalTable_ParseWrappedCmd(&e1Dataw, /* index into wrappedCmd */ + &len1, + &keyHandles, + &keyHandle1Index, /* index into key handles */ + &keyHandle2Index, + &ordw, + &transportWrappable, + &wrappedCmd); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Error parsing wrapped command\n"); + } + } + /* 3. If LEN1 is less than 0, or if ORDw is unknown, unimplemented, or cannot be determined + a. Return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (wrappedCmd.size < e1Dataw + len1) { + printf("TPM_Process_ExecuteTransport: Error (fatal), wrappedCmdSize %u e1 %u len1 %u\n", + wrappedCmd.size, e1Dataw, len1); + returnCode = TPM_FAIL; /* internal error, should never occur */ + } + } + /* allocate memory for the decrypted command, which is always the same length as the encrypted + command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&decryptCmd, wrappedCmd.size); + } + /* 4. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && + (len1 != 0)) { /* some commands have no DATAw area to encrypt */ + /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ + if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { + printf("TPM_Process_ExecuteTransport: Wrapped command MGF1 encrypted\n"); + /* i. Using the MGF1 function, create string G1 of length LEN1. The inputs to the MGF1 + are transLastNonceEven, transNonceOdd, "in", and T1 -> authData. These four values + concatenated together form the Z value that is the seed for the MGF1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ + len1, /* G1 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1 + + TPM_AUTHDATA_SIZE, /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("in") - 1, "in", + TPM_AUTHDATA_SIZE, t1TransportCopy.authData, + 0, NULL); + } + /* ii. Create C1 by performing an XOR of G1 and wrappedCmd starting at E1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Transport_CryptMgf1(decryptCmd, /* output */ + wrappedCmd.buffer, /* input */ + g1Mgf1, /* XOR pad */ + wrappedCmd.size, /* total size of buffers */ + e1Dataw, /* start of encrypted part */ + len1); /* length of encrypted part */ + } + } + /* b. If the encryption algorithm requires an IV or CTR calculate the IV or CTR value */ + else { + printf("TPM_Process_ExecuteTransport: " + "Wrapped command algId %08x encScheme %04hx encrypted\n", + t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); + /* This function call should not fail, as the parameters were checked at + TPM_EstablishTransport. The call is used here to get the block size. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportPublic_CheckEncScheme(&blockSize, + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* i. Using the MGF1 function, create string IV1 or CTR1 with a length set by the block + size of the encryption algorithm. The inputs to the MGF1 are transLastNonceEven, + transNonceOdd, and "in". These three values concatenated together form the Z value + that is the seed for the MGF1. Note that any terminating characters within the string + "in" are ignored, so a total of 42 bytes are hashed. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ + blockSize, /* G1 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1, + /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("in") - 1, "in", + 0, NULL); + } + /* ii. The symmetric key is taken from the first bytes of T1 -> authData. */ + /* iii. Decrypt DATAw and replace the DATAw area of E1 creating C1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Transport_CryptSymmetric(decryptCmd, /* output */ + wrappedCmd.buffer, /* input */ + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + t1TransportCopy.authData, /* key */ + TPM_AUTHDATA_SIZE, /* key size */ + g1Mgf1, /* pad, IV or CTR */ + blockSize, + wrappedCmd.size, /* total size of buffers */ + e1Dataw, /* start of encrypted part */ + len1); /* length of encrypted part */ + } + } + /* 4.c. TPM_OSAP, TPM_OIAP have no parameters encrypted */ + /* NOTE Handled by len1 = 0 */ + /* 4.d. TPM_DSAP has special rules for parameter encryption */ + /* NOTE Handled by setting inputHandleSize to all but entityValue */ + } + /* 5. Else (no encryption) */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Wrapped command not encrypted\n"); + /* a. Set C1 to the DATAw area E1 of wrappedCmd */ + memcpy(decryptCmd, wrappedCmd.buffer, wrappedCmd.size); + } + + /* Now that the wrapped command is decrypted, handle the special cases (e.g., TPM_FlushSpecific + and TPM_SaveContext) where the handle may or may not be a key handle, dependent on the value + of resourceType */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { + printf("TPM_Process_ExecuteTransport: key handles special case\n"); + + /* point to the resourceType in the decrypted stream, directly after the key handle */ + cmdStream = decryptCmd + keyHandle1Index + sizeof(TPM_KEY_HANDLE); + cmdStreamSize = wrappedCmd.size - keyHandle1Index - sizeof(TPM_KEY_HANDLE); + returnCode = TPM_Load32(&wrappedResourceType, &cmdStream , &cmdStreamSize ); + } + /* ii. If the resourceType is TPM_RT_KEY, then the public key MUST be logged */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { + printf("TPM_Process_ExecuteTransport: special case resource type %08x\n", + wrappedResourceType); + if (wrappedResourceType == TPM_RT_KEY) { + printf("TPM_Process_ExecuteTransport: Special case, 1 key handle\n"); + keyHandles = 1; + } + else { + keyHandles = 0; + } + } + + /* 6. Create H1 the SHA-1 of (ORDw || C1). */ + /* a. C1 MUST point at the decrypted DATAw area of E1 */ + /* b. The TPM MAY use this calculation for both execute transport authorization, authorization + of the wrapped command and transport log creation */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ExecuteTransport: DATAw decrypted", decryptCmd); + printf("TPM_Process_ExecuteTransport: Create H1\n"); + nOrdw = htonl(ordw); + returnCode = TPM_SHA1(h1InWrappedDigest, + sizeof(TPM_COMMAND_CODE), &nOrdw, + len1, decryptCmd + e1Dataw, + 0, NULL); + } + /* 7. Validate the incoming transport session authorization */ + /* a. Set inParamDigest to SHA-1 (ORDet || wrappedCmdSize || H1) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Validate AUTHet\n"); + nOrdet = htonl(ordinal); + nWrappedCmdSize = htonl(wrappedCmd.size); + returnCode = TPM_SHA1(inParamDigest, + sizeof(TPM_COMMAND_CODE), &nOrdet, + sizeof(uint32_t), &nWrappedCmdSize, + TPM_DIGEST_SIZE, h1InWrappedDigest, + 0, NULL); + } + /* b. Calculate the HMAC of (inParamDigest || transLastNonceEven || transNonceOdd || + continueTransSession) using T1 -> authData as the HMAC key */ + /* c. Validate transAuth, on errors return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportInternal_Check(inParamDigest, + &t1TransportCopy, /* transport session */ + transNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueTransSession, + transAuth); /* Authorization digest for input */ + } + /* 8. If TPM_ExecuteTransport requires auditing */ + /* a. Create TPM_AUDIT_EVENT_IN using H1 */ + /* NOTE: Done during response */ + /* 9. If ORDw is from the list of following commands return TPM_NO_WRAP_TRANSPORT */ + /* a. TPM_EstablishTransport */ + /* b. TPM_ExecuteTransport */ + /* c. TPM_ReleaseTransportSigned */ + if (returnCode == TPM_SUCCESS) { + if (!transportWrappable) { + printf("TPM_Process_ExecuteTransport: Error, ordinal %08x cannot be wrapped\n", + ordw); + returnCode = TPM_NO_WRAP_TRANSPORT; + } + } + /* 10. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + printf("TPM_Process_ExecuteTransport: Create transport log\n"); + /* a. Create L2 a TPM_TRANSPORT_LOG_IN structure */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* b. Set L2 -> parameters to H1 */ + TPM_Digest_Copy(l2TransportLogIn.parameters, h1InWrappedDigest); + /* c. If ORDw is a command with no key handles */ + /* i. Set L2 -> pubKeyHash to NULL */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + if ((returnCode == TPM_SUCCESS) && ((keyHandles == 1) || (keyHandles == 2))) { + if (returnCode == TPM_SUCCESS) { + /* point to the first key handle in the decrypted stream */ + cmdStream = decryptCmd + keyHandle1Index; + cmdStreamSize = wrappedCmd.size - keyHandle1Index; + /* get the key handle */ + returnCode = TPM_Load32(&keyHandle1, &cmdStream, &cmdStreamSize); + } + /* get the first key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 1 handle %08x\n", + keyHandle1); + returnCode = TPM_KeyHandleEntries_GetKey(&k2Key, + &parentPCRStatus, + tpm_state, + keyHandle1, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + TRUE); /* can use EK */ + } + /* 10.d. If ORDw is a command with one key handle */ + /* 10.i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by + the key handle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_SHA1_GenerateStructure(k2PubkeyDigest, + &(k2Key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + } + if ((returnCode == TPM_SUCCESS) && (keyHandles == 1)) { + printf("TPM_Process_ExecuteTransport: Digesting one public key\n"); + /* 10.ii. Set L2 -> pubKeyHash to SHA-1 (K2) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, + TPM_DIGEST_SIZE, k2PubkeyDigest, + 0, NULL); + } + } + /* 10.e. If ORDw is a command with two key handles */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 2)) { + printf("TPM_Process_ExecuteTransport: Digesting two public keys\n"); + /* i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the + first key handle. */ + /* NOTE Done above for 1 or 2 key case */ + if (returnCode == TPM_SUCCESS) { + /* point to the second key handle in the decrypted stream */ + cmdStream = decryptCmd + keyHandle2Index; + cmdStreamSize = wrappedCmd.size - keyHandle2Index; + /* get the key handle */ + returnCode = TPM_Load32(&keyHandle2, &cmdStream, &cmdStreamSize); + } + /* get the second key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 2 handle %08x\n", + keyHandle2); + returnCode = TPM_KeyHandleEntries_GetKey(&k3Key, + &parentPCRStatus, + tpm_state, + keyHandle2, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + TRUE); /* can use EK */ + } + /* ii. Create K3 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the + second key handle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_SHA1_GenerateStructure(k3PubkeyDigest, + &(k3Key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + /* 10.iii. Set L2 -> pubKeyHash to SHA-1 (K2 || K3) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, + TPM_DIGEST_SIZE, k2PubkeyDigest, + TPM_DIGEST_SIZE, k3PubkeyDigest, + 0, NULL); + } + } + /* 10.f. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L2) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Extend transDigest with input\n"); + returnCode = TPM_TransportLogIn_Extend(t1TransportCopy.transDigest, + &l2TransportLogIn); + } + /* 10.g. If ORDw is a command with key handles, and the key is not loaded, return + TPM_INVALID_KEYHANDLE. */ + /* NOTE Done by TPM_KeyHandleEntries_GetKey() */ + } + /* 11. Send the wrapped command to the normal TPM command parser, the output is C2 and the + return code is RCw */ + /* a. If ORDw is a command that is audited then the TPM MUST perform the input and output audit + of the command as part of this action */ + /* b. The TPM MAY use H1 as the data value in the authorization and audit calculations during + the execution of C1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Call wrapped command\n"); + returnCode = TPM_Process_Wrapped(&wrappedRspSbuffer, /* response buffer */ + decryptCmd, /* complete command array */ + wrappedCmd.size, /* actual bytes in command */ + tpm_state, + &t1TransportCopy); /* TPM_ExecuteTransport */ + printf("TPM_Process_ExecuteTransport: Completed wrapped command\n"); + } + /* 12. Set CT1 to TPM_STANY_DATA -> currentTicks -> currentTicks and return CT1 in the + currentTicks output parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); + } + if (returnCode == TPM_SUCCESS) { + TPM_Uint64_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Uint64_Store(¤tTicksSbuffer, + &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); + } + /* 13. Calculate S2 the pointer to the DATAw area of C2 */ + /* a. Calculate LEN2 the length of S2 according to the same rules that calculated LEN1 */ + if (returnCode == TPM_SUCCESS) { + /* get the response buffer and length */ + TPM_Sbuffer_Get(&wrappedRspSbuffer, &wrappedRspStream, &wrappedRspStreamSize); + /* parse the three standard input parameters, check paramSize against wrappedRsp->size */ + returnCode = TPM_OrdinalTable_ParseWrappedRsp(&s2Dataw, + &len2, + &rcw, + ordw, + wrappedRspStream, + wrappedRspStreamSize); + } + /* 14. Create H2 the SHA-1 of (RCw || ORDw || S2) */ + /* a. The TPM MAY use this calculation for execute transport authorization and transport log out + creation */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create H2\n"); + nRcw = htonl(rcw); + /* The TPM_ExecuteTransport input ordinal and output ordinal, currentTicks and locality are + not audited. This was simply an error, and not a deliberate attempt to make + TPM_ExecuteTransport different from other ordinals. */ + returnCode = TPM_SHA1(h2OutWrappedDigest, + sizeof(TPM_RESULT), &nRcw, + sizeof(TPM_COMMAND_CODE), &nOrdw, + len2, wrappedRspStream + s2Dataw, + 0, NULL); + } + /* 15. Calculate the outgoing transport session authorization */ + /* a. Create the new transNonceEven for the output of the command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Generate(t1TransportCopy.transNonceEven); + } + /* b. Set outParamDigest to SHA-1 (RCet || ORDet || TPM_STANY_DATA -> currentTicks -> + currentTicks || locality || wrappedRspSize || H2) */ + if (returnCode == TPM_SUCCESS) { + nRCet = htonl(returnCode); + TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); + nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); + nWrappedRspStreamSize = htonl(wrappedRspStreamSize); + returnCode = TPM_SHA1(outParamDigest, + sizeof(TPM_RESULT), &nRCet, + sizeof(TPM_COMMAND_CODE), &nOrdet, + currentTicksLength, currentTicksBuffer, + sizeof(TPM_MODIFIER_INDICATOR), &nLocality, + sizeof(uint32_t), &nWrappedRspStreamSize, + TPM_DIGEST_SIZE, h2OutWrappedDigest, + 0, NULL); + } + /* c. Calculate transAuth, the HMAC of (outParamDigest || transNonceEven || transNonceOdd || + continueTransSession) using T1 -> authData as the HMAC key */ + /* NOTE: Done as part of response */ + /* 16. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + /* a. Create L3 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* b. Set L3 -> parameters to H2 */ + TPM_Digest_Copy(l3TransportLogOut.parameters, h2OutWrappedDigest); + /* c. Set L3 -> currentTicks to TPM_STANY_DATA -> currentTicks */ + TPM_CurrentTicks_Copy(&(l3TransportLogOut.currentTicks), + &(tpm_state->tpm_stany_data.currentTicks)); + /* d. Set L3 -> locality to TPM_STANY_DATA -> localityModifier */ + l3TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* e. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L3) */ + printf("TPM_Process_ExecuteTransport: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TransportCopy.transDigest, + &l3TransportLogOut); + } + /* allocate memory for the encrypted response, which is always the same length as the decrypted + response */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&encryptRsp, wrappedRspStreamSize); + } + /* 17. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && + (len2 != 0)) { /* some commands have no DATAw area to encrypt */ + /* NOTE No TPM_OSAP encryption handled by len2 = 0 */ + /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ + if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { + printf("TPM_Process_ExecuteTransport: Wrapped response MGF1 encrypted\n"); + /* i. Using the MGF1 function, create string G2 of length LEN2. The inputs to the MGF1 + are transNonceEven, transNonceOdd, "out", and T1 -> authData. These four values + concatenated together form the Z value that is the seed for the MGF1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ + len2, /* G2 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1 + + TPM_AUTHDATA_SIZE, /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("out") - 1, "out", + TPM_AUTHDATA_SIZE, t1TransportCopy.authData, + 0, NULL); + } + /* ii. Create E2 by performing an XOR of G2 and C2 starting at S2. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Transport_CryptMgf1(encryptRsp, + wrappedRspStream, + g2Mgf1, + wrappedRspStreamSize, + s2Dataw, + len2); + } + } + /* b. Else */ + else { + printf("TPM_Process_ExecuteTransport: " + "Wrapped response algId %08x encScheme %04hx encrypted\n", + t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); + /* This function call should not fail, as the parameters were checked at + TPM_EstablishTransport. The call is used here to get the block size. + + This is a duplicate of the call for the command. However, there are cases where + there is no encrypted command (len1 == 0) so the call was not made. Rather than + keep track of whether blockSize is valid, it's clearer to just call the function + twice in some cases. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportPublic_CheckEncScheme(&blockSize, + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* i. Create IV2 or CTR2 using the same algorithm as IV1 or CTR1 with the input values + transNonceEven, transNonceOdd, and "out". Note that any terminating characters within + the string "out" are ignored, so a total of 43 bytes are hashed. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ + blockSize, /* G2 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1, + /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("out") - 1, "out", + 0, NULL); + } + /* ii. The symmetric key is taken from the first bytes of T1 -> authData */ + /* iii. Create E2 by encrypting C2 starting at S2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Transport_CryptSymmetric(encryptRsp, /* output */ + wrappedRspStream, /* input */ + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + t1TransportCopy.authData, /* key */ + TPM_AUTHDATA_SIZE, /* key size */ + g2Mgf1, /* pad, IV or CTR */ + blockSize, + wrappedRspStreamSize, /* total size of buffers */ + s2Dataw, /* start of encrypted part */ + len2); /* length of encrypted part */ + } + } + } + /* 18. Else (no encryption) */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Wrapped response not encrypted\n"); + /* a. Set E2 to the DATAw area S2 of wrappedRsp */ + memcpy(encryptRsp, wrappedRspStream ,wrappedRspStreamSize); + } + /* 19. If continueTransSession is FALSE */ + /* a. Invalidate all session data related to transHandle */ + /* NOTE: Done after response */ + /* 20. If TPM_ExecuteTranport requires auditing */ + /* a. Create TPM_AUDIT_EVENT_OUT using H2 */ + /* NOTE: Done during response */ + /* 21. Return C2 but with S2 replaced by E2 in the wrappedRsp parameter */ + if (returnCode == TPM_SUCCESS) { + /* if the wrapped command invalidated the transport session, set continueTransSession to + FALSE */ + if (!(t1TpmTransportInternal->valid)) { + continueTransSession = FALSE; + } + /* if the session is still valid, copy the copy back to the original so the log gets + updated */ + else { + TPM_TransportInternal_Copy(t1TpmTransportInternal, &t1TransportCopy); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ExecuteTransport: 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) { + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, currentTicksBuffer, currentTicksLength); + } + /* return locality */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return wrappedRspSize */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, wrappedRspStreamSize); + } + /* return wrappedRsp */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, encryptRsp, wrappedRspStreamSize); + } + /* non-standard - digest the above the line output parameters, H1 used */ + /* non-standard - calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportInternal_Set(response, + &t1TransportCopy, + outParamDigest, + transNonceOdd, + continueTransSession, + FALSE); /* transNonceEven already generated */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + FALSE, /* transportEncrypt */ + h1InWrappedDigest, + h2OutWrappedDigest, /* exception to normal digest */ + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueTransSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueTransSession) && + transHandleValid) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&wrappedCmd); /* @1 */ + TPM_SizedBuffer_Delete(&wrappedRsp); /* @2 */ + free(g1Mgf1); /* @3 */ + free (decryptCmd); /* @4 */ + TPM_TransportLogIn_Delete(&l2TransportLogIn); /* @5 */ + TPM_TransportLogOut_Delete(&l3TransportLogOut); /* @6 */ + TPM_Sbuffer_Delete(&wrappedRspSbuffer); /* @7 */ + TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ + free(g2Mgf1); /* @9 */ + TPM_TransportInternal_Delete(&t1TransportCopy); /* @10 */ + free(encryptRsp); /* @11 */ + return rcf; +} + +/* 24.3 TPM_ReleaseTransportSigned rev 101 + + This command completes the transport session. If logging for this session is turned on, then this + command returns a hash of all operations performed during the session along with a digital + signature of the hash. + + This command serves no purpose if logging is turned off, and results in an error if attempted. + + This command uses two authorization sessions, the key that will sign the log and the + authorization from the session. Having the session authorization proves that the requester that + is signing the log is the owner of the session. If this restriction is not put in then an + attacker can close the log and sign using their own key. + + The hash of the session log includes the information associated with the input phase of execution + of the TPM_ReleaseTransportSigned command. It cannot include the output phase information. +*/ + +TPM_RESULT TPM_Process_ReleaseTransportSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that will perform the signing */ + TPM_NONCE antiReplay; /* Value provided by caller for anti-replay protection */ + TPM_AUTHHANDLE authHandle; /* The authorization session to use key */ + TPM_NONCE authNonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest that authorizes the use + of key. HMAC key: key -> usageAuth */ + TPM_TRANSHANDLE transHandle; /* The transport session handle */ + TPM_NONCE transNonceOdd; /* Nonce supplied by caller for transport session */ + TPM_BOOL continueTransSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA transAuth; /* HMAC for transport session key: tranHandle -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_BOOL transHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal = NULL; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *keyUsageAuth; + TPM_TRANSPORT_LOG_OUT a1TransportLogOut; + TPM_SIGN_INFO h1SignInfo; + TPM_DIGEST h1Digest; /* digest of h1SignInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ + TPM_SIZED_BUFFER signature; /* The signature of the digest */ + + printf("TPM_Process_ReleaseTransportSigned: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&signature); /* freed @1 */ + TPM_TransportLogOut_Init(&a1TransportLogOut); /* freed @2 */ + TPM_SignInfo_Init(&h1SignInfo); /* freed @3 */ + /* + get inputs + + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseTransportSigned: keyHandle %08x\n", keyHandle ); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ReleaseTransportSigned: antiReplay", antiReplay); + 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_CheckRequestTag21(tag); + } + + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + authNonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + printf("TPM_Process_ReleaseTransportSigned: authHandle %08x\n", authHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&transHandle, + &transHandleValid, + transNonceOdd, + &continueTransSession, + transAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseTransportSigned: transHandle %08x\n", transHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseTransportSigned: 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) { + transHandleValid = FALSE; + } + /* + Processing + */ + /* if there is an active exclusive transport session and it's not this session, terminate it */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && + (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { + returnCode = + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions, + transHandle); + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_ReleaseTransportSigned: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ReleaseTransportSigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, if not return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (sigKey ->keyUsage != TPM_KEY_SIGNING) { + printf("TPM_Process_ReleaseTransportSigned: Error, keyUsage %04hx is invalid\n", + sigKey ->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Using key -> authData validate the command and parameters, on error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + authNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* 5. Using transHandle -> authData validate the command and parameters, on error return + TPM_AUTH2FAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportInternal_Check(inParamDigest, + t1TpmTransportInternal, /* transport session */ + transNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueTransSession, + transAuth); /* Authorization digest for input */ + } + /* 7. Else */ + if (returnCode == TPM_SUCCESS) { + if (!(t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + /* a. Return TPM_BAD_MODE */ + printf("TPM_Process_ReleaseTransportSigned: Error, TPM_TRANSPORT_LOG not set\n"); + returnCode = TPM_BAD_MODE; + } + } + /* 6. If T1 -> transAttributes has TPM_TRANSPORT_LOG set then update the current ticks + structure */ + if (returnCode == TPM_SUCCESS) { + currentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* a. Create A1 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* b. Set A1 -> parameters to the SHA-1 (ordinal || antiReplay) */ + TPM_Digest_Copy(a1TransportLogOut.parameters, inParamDigest); + /* c. Set A1 -> currentTicks to TPM_STANY_DATA -> currentTicks */ + TPM_CurrentTicks_Copy(&(a1TransportLogOut.currentTicks), currentTicks); + /* d. Set A1 -> locality to the locality modifier for this command */ + a1TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* e. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || A1) */ + printf("TPM_Process_ReleaseTransportSigned: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, + &a1TransportLogOut); + } + if (returnCode == TPM_SUCCESS) { + /* 8. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ + /* NOTE: Done by TPM_SignInfo_Init() */ + /* a. Set H1 -> fixed to "TRAN" */ + memcpy(h1SignInfo.fixed, "TRAN", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set H1 -> replay to antiReplay */ + TPM_Nonce_Copy(h1SignInfo.replay, antiReplay); + /* c. Set H1 -> data to T1 -> transDigest */ + returnCode = TPM_SizedBuffer_Set(&(h1SignInfo.data), + TPM_DIGEST_SIZE, + t1TpmTransportInternal->transDigest); + } + /* d. Sign SHA-1 hash of H1 using the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1Digest, &h1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + TPM_PrintAll("TPM_Process_ReleaseTransportSigned: h1Digest", h1Digest, TPM_DIGEST_SIZE); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&signature, /* signature */ + h1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* 9. Invalidate all session data related to T1 */ + /* NOTE Done after response */ + /* 10. Set continueTransSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueTransSession = FALSE; + } + /* 11. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseTransportSigned: 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 locality */ + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(response, currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* return signature */ + returnCode = TPM_SizedBuffer_Store(response, &signature); + /* 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 optional below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + authNonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportInternal_Set(response, + t1TpmTransportInternal, + outParamDigest, + transNonceOdd, + continueTransSession, + TRUE); /* generate transNonceEven */ + } + /* 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 continueTransSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueTransSession) && + transHandleValid) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* 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(&signature); /* @1 */ + TPM_TransportLogOut_Delete(&a1TransportLogOut); /* @2 */ + TPM_SignInfo_Delete(&h1SignInfo); /* @3 */ + return rcf; +} diff --git a/src/tpm12/tpm_transport.h b/src/tpm12/tpm_transport.h new file mode 100644 index 0000000..1bb70f7 --- /dev/null +++ b/src/tpm12/tpm_transport.h @@ -0,0 +1,211 @@ +/********************************************************************************/ +/* */ +/* Transport */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_transport.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#ifndef TPM_TRANSPORT_H +#define TPM_TRANSPORT_H + +#include "tpm_global.h" + +/* + Transport Encryption for wrapped commands and responses +*/ + +TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest, + const unsigned char *src, + const unsigned char *pad, + uint32_t size, + uint32_t index, + uint32_t len); + +TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest, + const unsigned char *src, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size, + uint32_t size, + uint32_t index, + uint32_t len); + +/* + Transport Sessions (the entire array) +*/ + +void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions); +void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions); + +void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_TRANSPORT_INTERNAL *transSessions); +void TPM_TransportSessions_GetSpace(uint32_t *space, + TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions); +TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal , + TPM_TRANSPORT_INTERNAL *transportSessions, + TPM_TRANSHANDLE transportHandle); +TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_TRANSPORT_INTERNAL *transSessions, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_TRANSHANDLE transportHandle, + TPM_TRANSHANDLE *transportExclusive); + +/* + TPM_TRANSPORT_PUBLIC +*/ + +void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public); +TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_PUBLIC *tpm_transport_public); +void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public); + +TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest, + const TPM_TRANSPORT_PUBLIC *src); +void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported, + TPM_ALGORITHM_ID algId); +TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + TPM_BOOL FIPS); + +/* + TPM_TRANSPORT_INTERNAL +*/ + +void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal); + +void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal, + TPM_TRANSPORT_INTERNAL *src_transport_internal); +TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_AUTHDATA transAuth); +TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_DIGEST outParamDigest, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_BOOL generateNonceEven); + +/* + TPM_TRANSPORT_LOG_IN +*/ + +void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); +TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); +void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); + +TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); + +/* + TPM_TRANSPORT_LOG_OUT +*/ + +void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); +TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); +void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); + +TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); + +/* + TPM_TRANSPORT_AUTH +*/ + +void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth); +TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_AUTH *tpm_transport_auth); +void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth); + +TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, + TPM_SIZED_BUFFER *secret, + TPM_KEY *tpm_key); + +/* Command Processing Functions */ + +TPM_RESULT TPM_Process_EstablishTransport(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 TPM_Process_ExecuteTransport(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 TPM_Process_ReleaseTransportSigned(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); + + +#endif diff --git a/src/tpm12/tpm_ver.c b/src/tpm12/tpm_ver.c new file mode 100644 index 0000000..a88154e --- /dev/null +++ b/src/tpm12/tpm_ver.c @@ -0,0 +1,273 @@ +/********************************************************************************/ +/* */ +/* Ver Structure Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ver.c 4071 2010-04-29 19:26:45Z 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_ver.h" + +/* + TPM_STRUCT_VER + + This indicates the version of the structure. + + Version 1.2 deprecates the use of this structure in all other structures. The structure is not + deprecated as many of the structures that contain this structure are not deprecated. + + The rationale behind keeping this structure and adding the new version structure is that in + version 1.1 this structure was in use for two purposes. The first was to indicate the structure + version, and in that mode the revMajor and revMinor were supposed to be set to 0. The second use + was in TPM_GetCapability and the structure would then return the correct revMajor and + revMinor. This use model caused problems in keeping track of when the revs were or were not set + and how software used the information. Version 1.2 went to structure tags. Some structures did not + change and the TPM_STRUCT_VER is still in use. To avoid the problems from 1.1 this structure now + is a fixed value and only remains for backwards compatibility. Structure versioning comes from the + tag on the structure and the TPM_GetCapability response for TPM versioning uses TPM_VERSION. +*/ + +/* TPM_StructVer_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StructVer_Init(TPM_STRUCT_VER *tpm_struct_ver) +{ + printf(" TPM_StructVer_Init:\n"); + tpm_struct_ver->major = 0x01; + tpm_struct_ver->minor = 0x01; + tpm_struct_ver->revMajor = 0x00; + tpm_struct_ver->revMinor = 0x00; + return; +} + +/* TPM_StructVer_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_StructVer_Load(TPM_STRUCT_VER *tpm_struct_ver, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_Load:\n"); + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->major), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->minor), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->revMajor), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->revMinor), stream, stream_size); + } + return rc; +} + + +/* TPM_StructVer_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StructVer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STRUCT_VER *tpm_struct_ver) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->major), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->minor), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->revMajor), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->revMinor), sizeof(BYTE)); + } + return rc; +} + +/* TPM_StructVer_Copy() copies the src to the destination. */ + +void TPM_StructVer_Copy(TPM_STRUCT_VER *tpm_struct_ver_dest, + TPM_STRUCT_VER *tpm_struct_ver_src) +{ + printf(" TPM_StructVer_Copy:\n"); + tpm_struct_ver_dest->major = tpm_struct_ver_src->major; + tpm_struct_ver_dest->minor = tpm_struct_ver_src->minor; + tpm_struct_ver_dest->revMajor = tpm_struct_ver_src->revMajor; + tpm_struct_ver_dest->revMinor = tpm_struct_ver_src->revMinor; + return; +} + +/* TPM_StructVer_CheckVer() checks that the major and minor version are 0x01, 0x01 */ + +TPM_RESULT TPM_StructVer_CheckVer(TPM_STRUCT_VER *tpm_struct_ver) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_CheckVer: version %u.%u.%u.%u\n", + tpm_struct_ver->major, + tpm_struct_ver->minor, + tpm_struct_ver->revMajor, + tpm_struct_ver->revMinor); + if ((tpm_struct_ver->major != 0x01) || + (tpm_struct_ver->minor != 0x01)) { + printf("TPM_StructVer_CheckVer: Error checking version\n"); + rc = TPM_BAD_VERSION; + } + return rc; +} + +/* + TPM_VERSION + + This structure provides information relative the version of the TPM. This structure should only be + in use by TPM_GetCapability to provide the information relative to the TPM. +*/ + +void TPM_Version_Init(TPM_VERSION *tpm_version) +{ + printf(" TPM_Version_Init:\n"); + tpm_version->major = 0; + tpm_version->minor = 0; + tpm_version->revMajor = 0; + tpm_version->revMinor = 0; + return; +} + +void TPM_Version_Set(TPM_VERSION *tpm_version, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + printf(" TPM_Version_Set:\n"); + /* This SHALL indicate the major version of the TPM, mostSigVer MUST be 0x01, leastSigVer MUST + be 0x00 */ + tpm_version->major = TPM_MAJOR; + /* This SHALL indicate the minor version of the TPM, mostSigVer MUST be 0x01 or 0x02, + leastSigVer MUST be 0x00 */ + tpm_version->minor = TPM_MINOR; + /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMajor */ + tpm_version->revMajor = tpm_permanent_data->revMajor; + /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMinor */ + tpm_version->revMinor = tpm_permanent_data->revMinor; + return; +} + +#if 0 +/* TPM_Version_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_Version_Init() +*/ + +TPM_RESULT TPM_Version_Load(TPM_VERSION *tpm_version, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Version_Load:\n"); + /* load major */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->major), stream, stream_size); + } + /* load minor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->minor), stream, stream_size); + } + /* load revMajor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->revMajor), stream, stream_size); + } + /* load revMinor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->revMinor), stream, stream_size); + } + return rc; +} +#endif +/* TPM_Version_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Version_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_VERSION *tpm_version) + +{ + TPM_RESULT rc = 0; + + printf(" TPM_Version_Store:\n"); + /* store major */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->major), sizeof(BYTE)); + } + /* store minor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->minor), sizeof(BYTE)); + } + /* store revMajor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->revMajor), sizeof(BYTE)); + } + /* store revMinor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->revMinor), sizeof(BYTE)); + } + return rc; +} diff --git a/src/tpm12/tpm_ver.h b/src/tpm12/tpm_ver.h new file mode 100644 index 0000000..5417bfe --- /dev/null +++ b/src/tpm12/tpm_ver.h @@ -0,0 +1,76 @@ +/********************************************************************************/ +/* */ +/* Ver Structure Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ver.h 4071 2010-04-29 19:26:45Z 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. */ +/********************************************************************************/ + +#ifndef TPM_VER_H +#define TPM_VER_H + +#include "tpm_types.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* TPM_STRUCT_VER */ + +void TPM_StructVer_Init(TPM_STRUCT_VER *tpm_struct_ver); +TPM_RESULT TPM_StructVer_Load(TPM_STRUCT_VER *tpm_struct_ver, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StructVer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STRUCT_VER *tpm_struct_ver); +void TPM_StructVer_Copy(TPM_STRUCT_VER *tpm_struct_ver_dest, + TPM_STRUCT_VER *tpm_struct_ver_src); +TPM_RESULT TPM_StructVer_CheckVer(TPM_STRUCT_VER *tpm_struct_ver); + +/* TPM_VERSION */ + +void TPM_Version_Init(TPM_VERSION *tpm_version); +void TPM_Version_Set(TPM_VERSION *tpm_version, + TPM_PERMANENT_DATA *tpm_permanent_data); +#if 0 +TPM_RESULT TPM_Version_Load(TPM_VERSION *tpm_version, + unsigned char **stream, + uint32_t *stream_size); +#endif +TPM_RESULT TPM_Version_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_VERSION *tpm_version); +void TPM_Version_Delete(TPM_VERSION *tpm_version); + + + + +#endif |