summaryrefslogtreecommitdiffstats
path: root/src/tpm12
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm12')
-rw-r--r--src/tpm12/tpm_admin.c2010
-rw-r--r--src/tpm12/tpm_admin.h141
-rw-r--r--src/tpm12/tpm_audit.c1271
-rw-r--r--src/tpm12/tpm_audit.h117
-rw-r--r--src/tpm12/tpm_auth.c2301
-rw-r--r--src/tpm12/tpm_auth.h180
-rw-r--r--src/tpm12/tpm_commands.h51
-rw-r--r--src/tpm12/tpm_constants.h1652
-rw-r--r--src/tpm12/tpm_counter.c1565
-rw-r--r--src/tpm12/tpm_counter.h140
-rw-r--r--src/tpm12/tpm_crypto.c3088
-rw-r--r--src/tpm12/tpm_crypto.h223
-rw-r--r--src/tpm12/tpm_crypto_freebl.c2652
-rw-r--r--src/tpm12/tpm_cryptoh.c5427
-rw-r--r--src/tpm12/tpm_cryptoh.h362
-rw-r--r--src/tpm12/tpm_daa.c5729
-rw-r--r--src/tpm12/tpm_daa.h405
-rw-r--r--src/tpm12/tpm_delegate.c3944
-rw-r--r--src/tpm12/tpm_delegate.h257
-rw-r--r--src/tpm12/tpm_digest.c162
-rw-r--r--src/tpm12/tpm_digest.h64
-rw-r--r--src/tpm12/tpm_error.c43
-rw-r--r--src/tpm12/tpm_global.c252
-rw-r--r--src/tpm12/tpm_global.h103
-rw-r--r--src/tpm12/tpm_identity.c1448
-rw-r--r--src/tpm12/tpm_identity.h138
-rw-r--r--src/tpm12/tpm_init.c1144
-rw-r--r--src/tpm12/tpm_init.h136
-rw-r--r--src/tpm12/tpm_io.h71
-rw-r--r--src/tpm12/tpm_key.c5529
-rw-r--r--src/tpm12/tpm_key.h457
-rw-r--r--src/tpm12/tpm_libtpms_io.c70
-rw-r--r--src/tpm12/tpm_load.c309
-rw-r--r--src/tpm12/tpm_load.h80
-rw-r--r--src/tpm12/tpm_maint.c1304
-rw-r--r--src/tpm12/tpm_maint.h89
-rw-r--r--src/tpm12/tpm_migration.c4287
-rw-r--r--src/tpm12/tpm_migration.h218
-rw-r--r--src/tpm12/tpm_nonce.c157
-rw-r--r--src/tpm12/tpm_nonce.h60
-rw-r--r--src/tpm12/tpm_nvram.c3747
-rw-r--r--src/tpm12/tpm_nvram.h201
-rw-r--r--src/tpm12/tpm_nvram_const.h138
-rw-r--r--src/tpm12/tpm_openssl_helpers.c135
-rw-r--r--src/tpm12/tpm_openssl_helpers.h50
-rw-r--r--src/tpm12/tpm_owner.c1968
-rw-r--r--src/tpm12/tpm_owner.h107
-rw-r--r--src/tpm12/tpm_pcr.c3800
-rw-r--r--src/tpm12/tpm_pcr.h367
-rw-r--r--src/tpm12/tpm_permanent.c1333
-rw-r--r--src/tpm12/tpm_permanent.h108
-rw-r--r--src/tpm12/tpm_platform.c175
-rw-r--r--src/tpm12/tpm_platform.h64
-rw-r--r--src/tpm12/tpm_process.c6051
-rw-r--r--src/tpm12/tpm_process.h298
-rw-r--r--src/tpm12/tpm_secret.c166
-rw-r--r--src/tpm12/tpm_secret.h62
-rw-r--r--src/tpm12/tpm_session.c5540
-rw-r--r--src/tpm12/tpm_session.h276
-rw-r--r--src/tpm12/tpm_sizedbuffer.c374
-rw-r--r--src/tpm12/tpm_sizedbuffer.h75
-rw-r--r--src/tpm12/tpm_startup.c1446
-rw-r--r--src/tpm12/tpm_startup.h136
-rw-r--r--src/tpm12/tpm_storage.c3593
-rw-r--r--src/tpm12/tpm_storage.h167
-rw-r--r--src/tpm12/tpm_store.c598
-rw-r--r--src/tpm12/tpm_store.h111
-rw-r--r--src/tpm12/tpm_structures.h2630
-rw-r--r--src/tpm12/tpm_svnrevision.c1
-rw-r--r--src/tpm12/tpm_svnrevision.h46
-rw-r--r--src/tpm12/tpm_ticks.c913
-rw-r--r--src/tpm12/tpm_ticks.h97
-rw-r--r--src/tpm12/tpm_time.c80
-rw-r--r--src/tpm12/tpm_time.h49
-rw-r--r--src/tpm12/tpm_transport.c2935
-rw-r--r--src/tpm12/tpm_transport.h211
-rw-r--r--src/tpm12/tpm_ver.c273
-rw-r--r--src/tpm12/tpm_ver.h76
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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get antiReplay parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(antiReplay, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ keyAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get auditState parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadBool(&auditState, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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(&currentTime, &tv_usec);
+ }
+ /* calculate how much time to wait */
+ if (rc == 0) {
+ printf(" TPM_Authdata_GetState: currentTime %u authFailTime %u\n",
+ currentTime, tpm_state->tpm_stclear_data.authFailTime);
+ /* how many failures over the threshold. The -1 makes threshold_diff 0 based, so the
+ first waitTime is 1 sec. */
+ threshold_diff = tpm_state->tpm_stclear_data.authFailCount - TPM_LOCKOUT_THRESHOLD - 1;
+ /* Wait time depends on how far over threshold, wait 1 sec and double each time. Ignore
+ shift overflow, since the previous timeout 0x80000000 sec is 68 years. */
+ waitTime = 0x01 << threshold_diff;
+ /* how far along is timeout. */
+ if (currentTime >= tpm_state->tpm_stclear_data.authFailTime) {
+ timeDiff = currentTime - tpm_state->tpm_stclear_data.authFailTime;
+ }
+ /* handle unlikely currentTime wrap around */
+ else {
+ timeDiff = ((0xffffffff - tpm_state->tpm_stclear_data.authFailTime) +
+ currentTime) + 1;
+ }
+ /* if not past the timeout, return an error */
+ printf(" TPM_Authdata_GetState: waitTime %u timeDiff %u\n",
+ waitTime, timeDiff);
+ if (waitTime > timeDiff) {
+ printf("TPM_Authdata_GetState: Error, timeout not complete\n");
+ *state = TPM_DA_STATE_ACTIVE;
+ *timeLeft = waitTime - timeDiff;
+ }
+ }
+ }
+ return rc;
+}
+
+/* TPM_Authdata_CheckState() checks the dictionary attack mitigation state.
+
+ This function is typically called at the beginning of each command.
+
+ If an attack is in progress, and the lockout timeout has not expired, an error is returned.
+*/
+
+TPM_RESULT TPM_Authdata_CheckState(tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ TPM_DA_STATE state;
+ uint32_t timeLeft;
+
+ printf(" TPM_Authdata_CheckState:\n");
+ /* Get the dictionary attack mitigation state */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&state, &timeLeft, tpm_state);
+ }
+ /* If not during the timeout period, allow the TPM_ResetLockValue ordinal */
+ if (rc == 0) {
+ if (state == TPM_DA_STATE_INACTIVE) {
+ tpm_state->tpm_stclear_data.disableResetLock = FALSE;
+ }
+ else { /* TPM_DA_STATE_ACTIVE */
+ rc = TPM_DEFEND_LOCK_RUNNING;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_CHANGEAUTH_VALIDATE
+*/
+
+/* TPM_ChangeauthValidate_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_ChangeauthValidate_Init(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ printf(" TPM_ChangeauthValidate_Init:\n");
+ TPM_Secret_Init(tpm_changeauth_validate->newAuthSecret);
+ TPM_Nonce_Init(tpm_changeauth_validate->n1);
+ return;
+}
+
+/* TPM_ChangeauthValidate_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_ChangeauthValidate_Init()
+ After use, call TPM_ChangeauthValidate_Delete() to free memory
+*/
+
+TPM_RESULT TPM_ChangeauthValidate_Load(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ChangeauthValidate_Load:\n");
+ /* load newAuthSecret */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_changeauth_validate->newAuthSecret, stream, stream_size);
+ }
+ /* load n1 */
+ if (rc == 0) {
+ rc = TPM_Nonce_Load(tpm_changeauth_validate->n1, stream, stream_size);
+ }
+ return rc;
+}
+
+#if 0
+/* TPM_ChangeauthValidate_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_ChangeauthValidate_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_ChangeauthValidate_Store:\n");
+ /* store newAuthSecret */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->newAuthSecret);
+ }
+ /* store n1 */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->n1);
+ }
+ return rc;
+}
+#endif
+
+/* TPM_ChangeauthValidate_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_ChangeauthValidate_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_ChangeauthValidate_Delete(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate)
+{
+ printf(" TPM_ChangeauthValidate_Delete:\n");
+ if (tpm_changeauth_validate != NULL) {
+ TPM_ChangeauthValidate_Init(tpm_changeauth_validate);
+ }
+ return;
+}
+
+/*
+ TPM_DA_INFO
+*/
+
+/* TPM_DaInfo_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DaInfo_Init(TPM_DA_INFO *tpm_da_info)
+{
+ printf(" TPM_DaInfo_Init:\n");
+/* tpm_da_info->tag = TPM_TAG_DA_INFO; */
+ tpm_da_info->state = TPM_DA_STATE_INACTIVE;
+ tpm_da_info->currentCount = 0;
+ tpm_da_info->thresholdCount = TPM_LOCKOUT_THRESHOLD;
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ tpm_da_info->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE;
+ tpm_da_info->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT;
+ tpm_da_info->actionDependValue = 0;
+ TPM_SizedBuffer_Init(&tpm_da_info->vendorData);
+ return;
+}
+
+/* TPM_DaInfo_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfo_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DA_INFO *tpm_da_info)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfo_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO);
+ }
+ /* store state */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info->state), sizeof(TPM_DA_STATE));
+ }
+ /* store currentCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->currentCount);
+ }
+ /* store thresholdCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->thresholdCount);
+ }
+ /* store actionAtThreshold */
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ /* store TPM_DA_ACTION_TYPE tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE);
+ }
+ /* store TPM_DA_ACTION_TYPE actions */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionAtThreshold.actions);
+ }
+ /* store actionDependValue */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionDependValue);
+ }
+ /* store vendorData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info->vendorData));
+ }
+ return rc;
+}
+
+/* TPM_DaInfo_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DaInfo_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DaInfo_Delete(TPM_DA_INFO *tpm_da_info)
+{
+ printf(" TPM_DaInfo_Delete:\n");
+ if (tpm_da_info != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_da_info->vendorData));
+ TPM_DaInfo_Init(tpm_da_info);
+ }
+ return;
+}
+
+/* TPM_DaInfoLimited_Set()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfo_Set(TPM_DA_INFO *tpm_da_info,
+ tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfo_Set:\n");
+ /* state: Dynamic. The actual state of the dictionary attack mitigation logic. */
+ /* actionDependValue: Dynamic. Action being taken when the dictionary attack mitigation logic
+ is active. E.g., when actionAtThreshold is TPM_DA_ACTION_TIMEOUT, this is the lockout time
+ remaining in seconds. */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&(tpm_da_info->state),
+ &(tpm_da_info->actionDependValue),
+ tpm_state);
+ }
+ /* Dynamic. The actual count of the authorization failure counter for the selected entity
+ type */
+ if (rc == 0) {
+ if (tpm_state->tpm_stclear_data.authFailCount <= 0xffff) {
+ tpm_da_info->currentCount = tpm_state->tpm_stclear_data.authFailCount;
+ }
+ /* with the doubling, this should never overflow. So overflow indicates a serious error */
+ else {
+ printf("TPM_DaInfo_Set: Error (fatal), authFailCount overflow %08x\n",
+ tpm_state->tpm_stclear_data.authFailCount);
+ rc = TPM_FAIL;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_DA_INFO_LIMITED
+*/
+
+/* TPM_DaInfoLimited_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DaInfoLimited_Init(TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ printf(" TPM_DaInfoLimited_Init:\n");
+/* tpm_da_info_limited->tag = TPM_TAG_DA_INFO_LIMITED; */
+ tpm_da_info_limited->state = TPM_DA_STATE_INACTIVE;
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ tpm_da_info_limited->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE;
+ tpm_da_info_limited->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT;
+ TPM_SizedBuffer_Init(&tpm_da_info_limited->vendorData);
+ return;
+}
+
+/* TPM_DaInfoLimited_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfoLimited_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DaInfoLimited_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO_LIMITED);
+ }
+ /* store state */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info_limited->state), sizeof (TPM_DA_STATE));
+ }
+ /* store actionAtThreshold */
+ /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */
+ /* store TPM_DA_ACTION_TYPE tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE);
+ }
+ /* store TPM_DA_ACTION_TYPE actions */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info_limited->actionAtThreshold.actions);
+ }
+ /* store vendorData */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info_limited->vendorData));
+ }
+ return rc;
+}
+
+/* TPM_DaInfoLimited_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DaInfoLimited_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DaInfoLimited_Delete(TPM_DA_INFO_LIMITED *tpm_da_info_limited)
+{
+ printf(" TPM_DaInfoLimited_Delete:\n");
+ if (tpm_da_info_limited != NULL) {
+ TPM_SizedBuffer_Delete(&(tpm_da_info_limited->vendorData));
+ TPM_DaInfoLimited_Init(tpm_da_info_limited);
+ }
+ return;
+}
+
+/* TPM_DaInfoLimited_Set()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DaInfoLimited_Set(TPM_DA_INFO_LIMITED *tpm_da_info_limited,
+ tpm_state_t *tpm_state)
+{
+ TPM_RESULT rc = 0;
+ uint32_t timeLeft;
+
+ printf(" TPM_DaInfoLimited_Set:\n");
+ /* Dynamic. The actual state of the dictionary attack mitigation logic. */
+ if (rc == 0) {
+ rc = TPM_Authdata_GetState(&(tpm_da_info_limited->state), &timeLeft, tpm_state);
+ }
+ return rc;
+}
+
+/*
+ Processing Functions
+*/
+
+
+/* 17.1 TPM_ChangeAuth rev 107
+
+ The TPM_ChangeAuth command allows the owner of an entity to change the authorization data for the
+ entity.
+
+ This command cannot invalidate the old entity. Therefore, the authorization change is only
+ effective if the application can guarantee that the old entity can be securely destroyed. If not,
+ two valid entities will exist, one with the old and one with the new authorization secret.
+
+ If this command is delegated, the delegated party can expand its key use privileges. That party
+ can create a copy of the key with known authorization, and it can then use the key without any
+ ordinal restrictions.
+
+ TPM_ChangeAuth requires the encryption of one parameter ("NewAuth"). For the sake of uniformity
+ with other commands that require the encryption of more than one parameter, the string used for
+ XOR encryption is generated by concatenating the evenNonce (created during the OSAP session) with
+ the session shared secret and then hashing the result.
+
+ The parameter list to this command must always include two authorization sessions, regardless of
+ the state of authDataUsage for the respective keys.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuth(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE parentHandle; /* Handle of the parent key to the entity. */
+ TPM_PROTOCOL_ID protocolID = 0; /* The protocol in use. */
+ TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */
+
+ TPM_AUTHHANDLE parentAuthHandle; /* The authorization handle used for the parent
+ key. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ parentAuthHandle */
+ TPM_BOOL continueAuthSession; /* Ignored, parentAuthHandle is always terminated. */
+ TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and
+ parentHandle. HMAC key: parentKey.usageAuth. */
+
+ TPM_AUTHHANDLE entityAuthHandle; /* The authorization handle used for the encrypted
+ entity. The session type MUST be OIAP */
+ TPM_NONCE entitynonceOdd; /* Nonce generated by system associated with
+ entityAuthHandle */
+ TPM_BOOL continueEntitySession; /* Ignored, entityAuthHandle is always terminated. */
+ TPM_AUTHDATA entityAuth; /* The authorization digest for the inputs and encrypted
+ entity. HMAC key: entity.usageAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL parentAuthHandleValid = FALSE;
+ TPM_BOOL entityAuthHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *parent_auth_session_data = NULL; /* session data for
+ parentAuthHandle */
+ TPM_AUTH_SESSION_DATA *entity_auth_session_data = NULL; /* session data for
+ entityAuthHandle */
+ TPM_KEY *parentKey = NULL;
+ TPM_SECRET *parentHmacKey;
+ TPM_SECRET *entityHmacKey;
+ TPM_SECRET saveKey; /* copy of entity HMAC key for response */
+ TPM_BOOL parentPCRStatus;
+ TPM_AUTHDATA decryptAuth;
+ unsigned char *b1DecryptData;
+ uint32_t b1DecryptDataLength = 0; /* actual valid data */
+ unsigned char *stream; /* for deserializing decrypted encData */
+ uint32_t stream_size;
+ TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */
+ TPM_SEALED_DATA sealEntity; /* entity structure when it's a TPM_ET_DATA */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */
+
+ printf("TPM_Process_ChangeAuth: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&encData); /* freed @1 */
+ TPM_SizedBuffer_Init(&outData); /* freed @2 */
+ b1DecryptData = NULL; /* freed @3 */
+ TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */
+ TPM_SealedData_Init(&sealEntity); /* freed @5 */
+ /*
+ get inputs
+ */
+ /* get parentHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&parentHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get protocolID parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: parentHandle %08x\n", parentHandle);
+ returnCode = TPM_Load16(&protocolID, &command, &paramSize);
+ }
+ /* get newAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: protocolID %04hx\n", protocolID);
+ returnCode = TPM_Authdata_Load(newAuth, &command, &paramSize);
+ }
+ /* get entityType parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get encData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: encDataSize %u\n", encData.size);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag2(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&parentAuthHandle,
+ &parentAuthHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ parentAuth,
+ &command, &paramSize);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: parentAuthHandle %08x\n", parentAuthHandle);
+ returnCode = TPM_AuthParams_Get(&entityAuthHandle,
+ &entityAuthHandleValid,
+ entitynonceOdd,
+ &continueEntitySession,
+ entityAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: entityAuthHandle %08x\n", entityAuthHandle);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuth: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ parentAuthHandleValid = FALSE;
+ entityAuthHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* Description
+ 1. The parentAuthHandle session type MUST be TPM_PID_OSAP.
+ 2. In this capability, the SRK cannot be accessed as entityType TPM_ET_KEY, since the SRK is
+ not wrapped by a parent key.
+ */
+ /* 1. Verify that entityType is one of TPM_ET_DATA, TPM_ET_KEY and return the error
+ TPM_WRONG_ENTITYTYPE if not. */
+ if (returnCode == TPM_SUCCESS) {
+ if ((entityType != TPM_ET_DATA) &&
+ (entityType != TPM_ET_KEY)) {
+ printf("TPM_Process_ChangeAuth: Error, bad entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* 2. Verify that parentAuthHandle session type is TPM_PID_OSAP return TPM_BAD_MODE on error */
+ /* get the key corresponding to the keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus,
+ tpm_state, parentHandle,
+ FALSE, /* not r/o, using to authenticate */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ /* get the OSAP session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&parent_auth_session_data,
+ &parentHmacKey,
+ tpm_state,
+ parentAuthHandle,
+ TPM_PID_OSAP,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ parentKey,
+ NULL, /* OIAP */
+ parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/
+ }
+ /* 3. Verify that entityAuthHandle session type is TPM_PID_OIAP return TPM_BAD_MODE on error */
+ /* keyEntity and sealEntity are not valid yet, so pass in NULL and ignore the returned
+ entityHmacKey */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&entity_auth_session_data,
+ &entityHmacKey,
+ tpm_state,
+ entityAuthHandle,
+ TPM_PID_OIAP,
+ 0, /* OSAP entity type */
+ ordinal,
+ NULL,
+ NULL,
+ NULL);
+ }
+ /* 4.If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */
+ if (returnCode == TPM_SUCCESS) {
+ if (protocolID != TPM_PID_ADCP) {
+ printf("TPM_Process_ChangeAuth: Error, bad protocolID\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 5. The encData field MUST be the encData field from either the TPM_STORED_DATA or TPM_KEY
+ structures. */
+ /* NOTE Seems the same as Action 1. */
+ /* 6. Create decryptAuth by decrypting newAuth according to the ADIP indicated by
+ parentHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(decryptAuth,
+ NULL,
+ newAuth,
+ parent_auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* odd and even */
+ }
+ /* 7. The TPM MUST validate the command using the authorization data in the parentAuth parameter
+ */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *parentHmacKey, /* HMAC key */
+ inParamDigest,
+ parent_auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ parentAuth); /* Authorization digest for input */
+ }
+ /* 8. Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return
+ TPM_INVALID_KEYUSAGE */
+ if (returnCode == TPM_SUCCESS) {
+ if (parentKey->keyUsage != TPM_KEY_STORAGE) {
+ printf("TPM_Process_ChangeAuth: Error, keyUsage %04hx is invalid\n",
+ parentKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 9. After parameter validation the TPM creates b1 by decrypting encData using the key pointed
+ to by parentHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&b1DecryptData, /* decrypted data */
+ &b1DecryptDataLength, /* actual size of
+ decrypted data */
+ encData.buffer,/* encrypted data */
+ encData.size, /* encrypted data size */
+ parentKey);
+ }
+ if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_KEY)) {
+ printf("TPM_Process_ChangeAuth: entityType is TPM_ET_KEY\n");
+ /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or
+ a TPM_SEALED_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ stream = b1DecryptData;
+ stream_size = b1DecryptDataLength;
+ returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE,
+ &stream, &stream_size,
+ NULL, /* TPM_KEY_PARMS */
+ NULL); /* TPM_SIZED_BUFFER pubKey */
+ }
+ /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */
+ /* NOTE: Done by TPM_StoreAsymkey_Load() */
+ if (returnCode == TPM_SUCCESS) {
+ /* save a copy of the HMAC key for the response before changing */
+ TPM_Secret_Copy(saveKey, keyEntity.usageAuth);
+ /* a.The TPM must validate the command using the authorization data entityAuth
+ parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA ->
+ authData. */
+ returnCode = TPM_Auth2data_Check(tpm_state,
+ keyEntity.usageAuth, /* HMAC key */
+ inParamDigest,
+ entity_auth_session_data, /* authorization session */
+ entitynonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueEntitySession,
+ entityAuth); /* Authorization digest for input */
+ }
+ /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth was", keyEntity.usageAuth);
+ TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth now", decryptAuth);
+ TPM_Secret_Copy(keyEntity.usageAuth, decryptAuth);
+ }
+ /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the
+ parentKeyHandle to provide the key information. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey);
+ }
+ }
+ else if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_DATA)) {
+ printf("TPM_Process_ChangeAuth: entityType is TPM_ET_DATA\n");
+ /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or
+ a TPM_SEALED_DATA */
+ if (returnCode == TPM_SUCCESS) {
+ stream = b1DecryptData;
+ stream_size = b1DecryptDataLength;
+ returnCode = TPM_SealedData_Load(&sealEntity, &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuth: Checking tpmProof\n");
+ returnCode = TPM_Secret_Compare(sealEntity.tpmProof,
+ tpm_state->tpm_permanent_data.tpmProof);
+ }
+ /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */
+ /* NOTE: Done by TPM_SealedData_Load() */
+ if (returnCode == TPM_SUCCESS) {
+ /* save a copy of the HMAC key for the response before changing */
+ TPM_Secret_Copy(saveKey, sealEntity.authData);
+ /* a.The TPM must validate the command using the authorization data entityAuth
+ parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA ->
+ authData. */
+ returnCode = TPM_Auth2data_Check(tpm_state,
+ sealEntity.authData, /* HMAC key */
+ inParamDigest,
+ entity_auth_session_data, /* authorization session */
+ entitynonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueEntitySession,
+ entityAuth); /* Authorization digest for input */
+ }
+ /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuth: authData was", sealEntity.authData);
+ TPM_PrintFour("TPM_Process_ChangeAuth: authData now", decryptAuth);
+ TPM_Secret_Copy(sealEntity.authData, decryptAuth);
+ }
+ /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the
+ parentKeyHandle to provide the key information. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SealedData_GenerateEncData(&outData, &sealEntity, parentKey);
+ }
+ }
+ /* 13. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle
+ sessions. */
+ if (returnCode == TPM_SUCCESS) {
+ continueAuthSession = FALSE;
+ continueEntitySession = FALSE;
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuth: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 14. The new blob is returned in outData when appropriate. */
+ returnCode = TPM_SizedBuffer_Store(response, &outData);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *parentHmacKey, /* HMAC key */
+ parent_auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ saveKey, /* the original and not the new auth value */
+ entity_auth_session_data,
+ outParamDigest,
+ entitynonceOdd,
+ continueEntitySession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* 15. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle
+ sessions. */
+ if (parentAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, parentAuthHandle);
+ }
+ if (entityAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, entityAuthHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&encData); /* @1 */
+ TPM_SizedBuffer_Delete(&outData); /* @2 */
+ free(b1DecryptData); /* @3 */
+ TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */
+ TPM_SealedData_Delete(&sealEntity); /* @5 */
+ return rcf;
+}
+
+/* 17.2 TPM_ChangeAuthOwner rev 98
+
+ The TPM_ChangeAuthOwner command allows the owner of an entity to change the authorization data
+ for the TPM Owner or the SRK.
+
+ This command requires authorization from the current TPM Owner to execute.
+
+ TPM's targeted for an environment (e.g. a server) with long lasting sessions should not
+ invalidate all sessions.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthOwner(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_PROTOCOL_ID protocolID; /* The protocol in use. */
+ TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_AUTHHANDLE ownerAuthHandle; /* The authorization handle used for the TPM
+ Owner. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with ownerAuthHandle
+ */
+ TPM_BOOL continueAuthSession = TRUE; /* Continue use flag the TPM ignores this value */
+ TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and ownerHandle. HMAC
+ key: tpmOwnerAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL ownerAuthHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *owner_auth_session_data = NULL; /* session data for ownerAuthHandle
+ */
+ TPM_SECRET *hmacKey;
+ TPM_SECRET saveKey; /* copy of HMAC key, since sessions invalidated */
+ TPM_AUTHDATA decryptAuth;
+ TPM_AUTHDATA *entityAuth; /* pointer to either owner or SRK auth */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_ChangeAuthOwner: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get protocolID parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&protocolID, &command, &paramSize);
+ }
+ /* get newAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthOwner: protocolID %04hx\n", protocolID);
+ returnCode = TPM_Authdata_Load(newAuth, &command, &paramSize);
+ }
+ /* get entityType parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&ownerAuthHandle,
+ &ownerAuthHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthOwner: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ ownerAuthHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM MUST validate the command using the AuthData in the ownerAuth parameter */
+ /* 2. The ownerAuthHandle session type MUST be TPM_PID_OSAP */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&owner_auth_session_data,
+ &hmacKey,
+ tpm_state,
+ ownerAuthHandle,
+ TPM_PID_OSAP,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ NULL,
+ tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ owner_auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 3. If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */
+ if (returnCode == TPM_SUCCESS) {
+ if (protocolID != TPM_PID_ADCP) {
+ printf("TPM_Process_ChangeAuthOwner: Error, bad protocolID\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 4. Verify that entityType is either TPM_ET_OWNER or TPM_ET_SRK, and return the error
+ TPM_WRONG_ENTITYTYPE if not. */
+ if (returnCode == TPM_SUCCESS) {
+ if (entityType == TPM_ET_OWNER) {
+ printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_OWNER\n");
+ entityAuth = &(tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ else if (entityType == TPM_ET_SRK) {
+ printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_SRK\n");
+ entityAuth = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->usageAuth);
+ }
+ else {
+ entityAuth = NULL; /* just to quiet the compiler */
+ printf("TPM_Process_ChangeAuthOwner: Error, wrong entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* 5. Create decryptAuth by decrypting newAuth according to the ADIP indicated by
+ ownerAuthHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(decryptAuth,
+ NULL,
+ newAuth,
+ owner_auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* even and odd */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_ChangeAuthOwner: From entityAuth", *entityAuth);
+ TPM_PrintFour("TPM_Process_ChangeAuthOwner: To decryptAuth", decryptAuth);
+ /* 6. The TPM MUST enforce the destruction of the ownerAuthHandle session upon completion of
+ this command (successful or unsuccessful). This includes setting continueAuthSession to
+ FALSE */
+ continueAuthSession = FALSE;
+ /* 7. Set the authorization data for the indicated entity to decryptAuth */
+ TPM_Secret_Copy(*entityAuth, decryptAuth);
+ /* save a copy of the HMAC key for the response before invalidating */
+ TPM_Secret_Copy(saveKey, *hmacKey);
+ /* 8. The TPM MUST invalidate all owner authorized OSAP and DSAP sessions, active or
+ saved. */
+ TPM_AuthSessions_TerminateEntity(&continueAuthSession,
+ ownerAuthHandle,
+ tpm_state->tpm_stclear_data.authSessions,
+ TPM_ET_OWNER, /* TPM_ENTITY_TYPE */
+ NULL); /* ignore entityDigest */
+ /* 9. The TPM MAY invalidate all sessions, active or saved */
+ /* Store the permanent data back to NVRAM */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ TRUE,
+ returnCode);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuthOwner: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ saveKey, /* HMAC key */
+ owner_auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ ownerAuthHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, ownerAuthHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+
+/* 27.4.1 TPM_ChangeAuthAsymStart rev 87
+
+ The TPM_ChangeAuthAsymStart starts the process of changing AuthData for an entity. It sets up an
+ OIAP session that must be retained for use by its twin TPM_ChangeAuthAsymFinish command.
+
+ TPM_ChangeAuthAsymStart creates a temporary asymmetric public key "tempkey" to provide
+ confidentiality for new AuthData to be sent to the TPM. TPM_ChangeAuthAsymStart certifies that
+ tempkey was generated by a genuine TPM, by generating a certifyInfo structure that is signed by a
+ TPM identity. The owner of that TPM identity must cooperate to produce this command, because
+ TPM_ChangeAuthAsymStart requires authorization to use that identity.
+
+ It is envisaged that tempkey and certifyInfo are given to the owner of the entity whose
+ authorization is to be changed. That owner uses certifyInfo and a TPM_IDENTITY_CREDENTIAL to
+ verify that tempkey was generated by a genuine TPM. This is done by verifying the
+ TPM_IDENTITY_CREDENTIAL using the public key of a CA, verifying the signature on the certifyInfo
+ structure with the public key of the identity in TPM_IDENTITY_CREDENTIAL, and verifying tempkey
+ by comparing its digest with the value inside certifyInfo. The owner uses tempkey to encrypt the
+ desired new AuthData and inserts that encrypted data in a TPM_ChangeAuthAsymFinish command, in
+ the knowledge that only a TPM with a specific identity can interpret the new AuthData.
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthAsymStart(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE idHandle; /* The keyHandle identifier of a loaded identity ID key */
+ TPM_NONCE antiReplay; /* The nonce to be inserted into the certifyInfo structure
+ */
+ TPM_KEY_PARMS tempKeyParms; /* Structure contains all parameters of ephemeral key. */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for idHandle
+ authorization. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session
+ handle */
+ TPM_AUTHDATA idAuth; /* Authorization. HMAC key: idKey.usageAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY *idKey = NULL;
+ TPM_SECRET *idKeyUsageAuth;
+ TPM_BOOL idPCRStatus;
+ TPM_RSA_KEY_PARMS *temp_rsa_key_parms; /* tempKey is RSA */
+ TPM_BOOL key_added = FALSE; /* added to key handle entries */
+ TPM_DIGEST h1Digest;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_CERTIFY_INFO certifyInfo; /* The certifyInfo structure that is to be signed. */
+ TPM_SIZED_BUFFER sig; /* The signature of the certifyInfo parameter. */
+ TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier to be used by
+ ChangeAuthAsymFinish for the ephemeral key */
+ TPM_KEY *tempKey; /* Structure containing all parameters and public part of
+ ephemeral key. TPM_KEY.encSize is set to 0. NOTE
+ Actually tempKey and k1 are the same. The encData is
+ present but not returned in the response. */
+
+ printf("TPM_Process_ChangeAuthAsymStart: Ordinal Entry\n");
+ TPM_KeyParms_Init(&tempKeyParms); /* freed @1 */
+ TPM_CertifyInfo_Init(&certifyInfo); /* freed @2 */
+ TPM_SizedBuffer_Init(&sig); /* freed @3 */
+ tempKey = NULL; /* freed @4 */
+ /*
+ get inputs
+ */
+ /* get idHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&idHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: idHandle %08x\n", idHandle);
+ /* get antiReplay parameter */
+ returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
+ }
+ /* get tempKey (actually tempKeyParms) parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_Load(&tempKeyParms, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ idAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthAsymStart: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM SHALL verify the AuthData to use the TPM identity key held in idHandle. The TPM
+ MUST verify that the key is a TPM identity key.*/
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&idKey, &idPCRStatus, tpm_state, idHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (idKey->keyUsage != TPM_KEY_IDENTITY) {
+ printf("TPM_Process_ChangeAuthAsymStart: Error, keyUsage %04hx is invalid\n",
+ idKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){
+ if (idKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_ChangeAuthAsymStart: Error, authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get idHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Key_GetUsageAuth(&idKeyUsageAuth, idKey);
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ idKey,
+ idKeyUsageAuth, /* OIAP */
+ idKey->tpm_store_asymkey->pubDataDigest); /* OSAP */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ idAuth); /* Authorization digest for input */
+ }
+ /* 2. The TPM SHALL validate the algorithm parameters for the key to create from the tempKey
+ parameter. */
+ if (returnCode == TPM_SUCCESS) {
+ /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */
+ /* 3. Recommended key type is RSA */
+ returnCode = TPM_KeyParms_GetRSAKeyParms(&temp_rsa_key_parms, &tempKeyParms);
+ }
+ /* 4. Minimum RSA key size MUST is 512 bits, recommended RSA key size is 1024 */
+ /* 5. For other key types the minimum key size strength MUST be comparable to RSA 512 */
+ /* 6. If the TPM is not designed to create a key of the requested type, return the error code
+ TPM_BAD_KEY_PROPERTY */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_CheckProperties(&tempKeyParms,
+ TPM_KEY_AUTHCHANGE,
+ 0, /* required key length in bits */
+ tpm_state->tpm_permanent_flags.FIPS);
+ }
+ /* 7. The TPM SHALL create a new key (k1) in accordance with the algorithm parameter. The newly
+ created key is pointed to by ephHandle. */
+ /* NOTE tempKey is used as k1 */
+ /* Allocate space for k1. The key cannot be a local variable, since it persists in key storage
+ after the command completes. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Malloc((unsigned char **)&tempKey, sizeof(TPM_KEY));
+ }
+ /*
+ Field Descriptions for certifyInfo parameter
+ Type Name Description
+ TPM_VERSION Version TPM version structure; Part 2 TPM_VERSION
+ keyFlags Redirection This SHALL be set to FALSE
+ Migratable This SHALL be set to FALSE
+ Volatile This SHALL be set to TRUE
+ TPM_AUTH_DATA_USAGE authDataUsage This SHALL be set to TPM_AUTH_NEVER
+ TPM_KEY_USAGE KeyUsage This SHALL be set to TPM_KEY_AUTHCHANGE
+ uint32_t PCRInfoSize This SHALL be set to 0
+ TPM_DIGEST pubDigest This SHALL be the hash of the public key
+ being certified.
+ TPM_NONCE Data This SHALL be set to antiReplay
+ TPM_KEY_PARMS info This specifies the type of key and its parameters.
+ TPM_BOOL parentPCRStatus This SHALL be set to FALSE.
+ */
+ /* generate a TPM_KEY using TPM_KEY_PARMS. encData is stored as clear text since there is no
+ parent key for the ephemeral key */
+ if (returnCode == TPM_SUCCESS) {
+ /* This must immediately follow the successful malloc, so the _Delete / free work */
+ TPM_Key_Init(tempKey);
+ printf(" TPM_Process_ChangeAuthAsymStart: Creating ephemeral key\n");
+ returnCode = TPM_Key_GenerateRSA(tempKey,
+ tpm_state,
+ NULL, /* encData cleartext */
+ tpm_state->tpm_stclear_data.PCRS, /* PCR array */
+ 1, /* TPM_KEY */
+ TPM_KEY_AUTHCHANGE, /* keyUsage */
+ TPM_ISVOLATILE, /* keyFlags */
+ TPM_AUTH_NEVER, /* authDataUsage */
+ &tempKeyParms, /* TPM_KEY_PARMS */
+ NULL, /* TPM_PCR_INFO */
+ NULL); /* TPM_PCR_INFO_LONG */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ ephHandle = 0; /* no preferred value */
+ returnCode = TPM_KeyHandleEntries_AddKeyEntry(&ephHandle, /* output */
+ tpm_state->tpm_key_handle_entries, /* input */
+ tempKey, /* input */
+ 0, /* parentPCRStatus not used */
+ 0); /* keyControl not used */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: Ephemeral key handle %08x\n", ephHandle);
+ /* remember that the handle has been added to handle list, so it can be deleted on error */
+ key_added = TRUE;
+ }
+ /* 8. The TPM SHALL fill in all fields in tempKey using k1 for the information. The TPM_KEY ->
+ encSize MUST be 0. */
+ /* NOTE Not required. k1 and tempKey are the same */
+ /* 9. The TPM SHALL fill in certifyInfo using k1 for the information. The certifyInfo -> data
+ field is supplied by the antiReplay. */
+ if (returnCode == TPM_SUCCESS) {
+ printf(" TPM_Process_ChangeAuthAsymStart: Creating certifyInfo\n");
+ TPM_Nonce_Copy(certifyInfo.data, antiReplay);
+ returnCode = TPM_CertifyInfo_Set(&certifyInfo, tempKey);
+ }
+ /* 10. The TPM then signs the certifyInfo parameter using the key pointed to by idHandle. The
+ resulting signed blob is returned in sig parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SHA1_GenerateStructure(h1Digest, &certifyInfo,
+ (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymStart: Signing certifyInfo digest\n");
+ returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */
+ h1Digest, /* message */
+ TPM_DIGEST_SIZE, /* message size */
+ idKey); /* input, signing key */
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuthAsymStart: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return certifyInfo */
+ returnCode = TPM_CertifyInfo_Store(response, &certifyInfo);
+ }
+ /* return sig */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Store(response, &sig);
+ }
+ /* return ephHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Sbuffer_Append32(response, ephHandle);
+ }
+ /* return tempKey. TPM_Key_StorePubData() does not store any encData. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_StorePubData(response, FALSE, tempKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* TPM_KEY.encSize is set to 0 */
+ returnCode = TPM_Sbuffer_Append32(response, 0);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_KeyParms_Delete(&tempKeyParms); /* @1 */
+ TPM_CertifyInfo_Delete(&certifyInfo); /* @2 */
+ TPM_SizedBuffer_Delete(&sig); /* @3 */
+ /* if there was a failure, delete inKey */
+ if ((rcf != 0) ||
+ (returnCode != TPM_SUCCESS)) {
+ TPM_Key_Delete(tempKey); /* @4 */
+ free(tempKey); /* @4 */
+ if (key_added) {
+ /* if there was a failure and tempKey was stored in the handle list, free the handle.
+ Ignore errors, since only one error code can be returned. */
+ TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, ephHandle);
+ }
+ }
+ return rcf;
+}
+
+/* 27.4.2 TPM_ChangeAuthAsymFinish rev 110
+
+ The TPM_ChangeAuthAsymFinish command allows the owner of an entity to change the AuthData for the
+ entity.
+
+ The command requires the cooperation of the owner of the parent of the entity, since AuthData
+ must be provided to use that parent entity. The command requires knowledge of the existing
+ AuthData information and passes the new AuthData information. The newAuthLink parameter proves
+ knowledge of existing AuthData information and new AuthData information. The new AuthData
+ information "encNewAuth" is encrypted using the "tempKey" variable obtained via
+ TPM_ChangeAuthAsymStart.
+
+ A parent therefore retains control over a change in the AuthData of a child, but is prevented
+ from knowing the new AuthData for that child.
+
+ The changeProof parameter provides a proof that the new AuthData value was properly inserted into
+ the entity. The inclusion of a nonce from the TPM provides an entropy source in the case where
+ the AuthData value may be in itself be a low entropy value (hash of a password etc).
+*/
+
+TPM_RESULT TPM_Process_ChangeAuthAsymFinish(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE parentHandle; /* The keyHandle of the parent key for the input
+ data */
+ TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier for the ephemeral key */
+ TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */
+ TPM_HMAC newAuthLink; /* HMAC calculation that links the old and new
+ AuthData values together */
+ TPM_SIZED_BUFFER encNewAuth; /* New AuthData encrypted with ephemeral key. */
+ TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */
+ TPM_AUTHHANDLE authHandle; /* Authorization for parent key. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL continueAuthSession; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA privAuth; /* The authorization session digest for inputs and
+ parentHandle. HMAC key: parentKey.usageAuth. */
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_KEY *parentKey = NULL;
+ TPM_SECRET *parentKeyUsageAuth;
+ TPM_BOOL parentPCRStatus;
+ TPM_KEY *ephKey = NULL;
+ TPM_BOOL ephPCRStatus;
+ unsigned char *stream; /* for deserializing decrypted encData */
+ uint32_t stream_size;
+ TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */
+ unsigned char *e1DecryptData;
+ uint32_t e1DecryptDataLength = 0; /* actual valid data */
+ unsigned char *a1Auth;
+ uint32_t a1AuthLength = 0; /* actual valid data */
+ TPM_CHANGEAUTH_VALIDATE changeauthValidate;
+ TPM_BOOL valid;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */
+ TPM_NONCE saltNonce; /* A nonce value from the TPM RNG to add entropy to the
+ changeProof value */
+ TPM_DIGEST changeProof; /* Proof that AuthData has changed. */
+
+ printf("TPM_Process_ChangeAuthAsymFinish: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&encNewAuth); /* freed @1 */
+ TPM_SizedBuffer_Init(&encData); /* freed @2 */
+ TPM_SizedBuffer_Init(&outData); /* freed @3 */
+ TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */
+ e1DecryptData = NULL; /* freed @5 */
+ a1Auth = NULL; /* freed @6 */
+ TPM_ChangeauthValidate_Init(&changeauthValidate); /* freed @7 */
+ /*
+ get inputs
+ */
+ /* get parentHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&parentHandle, &command, &paramSize);
+ }
+ /* get ephHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: parentHandle %08x\n", parentHandle);
+ returnCode = TPM_Load32(&ephHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: ephHandle %08x\n", ephHandle);
+ /* get entityType parameter */
+ returnCode = TPM_Load16(&entityType, &command, &paramSize);
+ }
+ /* get newAuthLink parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(newAuthLink, &command, &paramSize);
+ }
+ /* get encNewAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encNewAuth, &command, &paramSize);
+ }
+ /* get encData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: encDataSize %u\n", encData.size);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM SHALL validate that the authHandle parameter authorizes use of the key in
+ parentHandle.*/
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus,
+ tpm_state, parentHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){
+ if (parentKey->authDataUsage != TPM_AUTH_NEVER) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, authorization required\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ /* get idHandle -> usageAuth */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if (parentHandle != TPM_KH_SRK) {
+ returnCode = TPM_Key_GetUsageAuth(&parentKeyUsageAuth, parentKey);
+ }
+ /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner
+ authorization. */
+ else {
+ parentKeyUsageAuth = &(tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ }
+ /* get the session data */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if (parentHandle != TPM_KH_SRK) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ parentKey,
+ parentKeyUsageAuth, /* OIAP */
+ parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/
+ }
+ /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner
+ authorization. */
+ else {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ parentKey,
+ parentKeyUsageAuth, /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /*OSAP*/
+ }
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ privAuth); /* Authorization digest for input */
+ }
+ /* 2. The encData field MUST be the encData field from TPM_STORED_DATA or TPM_KEY. */
+ if (returnCode == TPM_SUCCESS) {
+ /* FIXME currently only TPM_KEY supported */
+ if (entityType != TPM_ET_KEY) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, bad entityType %04x\n", entityType);
+ returnCode = TPM_WRONG_ENTITYTYPE;
+ }
+ }
+ /* Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return the error code
+ TPM_INVALID_KEYUSAGE */
+ if (returnCode == TPM_SUCCESS) {
+ if (parentKey->keyUsage != TPM_KEY_STORAGE) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, keyUsage %04hx is invalid\n",
+ parentKey->keyUsage);
+ returnCode = TPM_INVALID_KEYUSAGE;
+ }
+ }
+ /* 3. The TPM SHALL create e1 by decrypting the entity held in the encData parameter. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&e1DecryptData, /* decrypted data */
+ &e1DecryptDataLength, /* actual size of decrypted
+ data */
+ encData.buffer,/* encrypted data */
+ encData.size, /* encrypted data size */
+ parentKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ stream = e1DecryptData;
+ stream_size = e1DecryptDataLength;
+ returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE,
+ &stream, &stream_size,
+ NULL, /* TPM_KEY_PARMS */
+ NULL); /* TPM_SIZED_BUFFER pubKey */
+ }
+ /* 4. The TPM SHALL create a1 by decrypting encNewAuth using the ephHandle ->
+ TPM_KEY_AUTHCHANGE private key. a1 is a structure of type TPM_CHANGEAUTH_VALIDATE. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&ephKey, &ephPCRStatus, tpm_state, ephHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (ephKey->keyUsage != TPM_KEY_AUTHCHANGE) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error: "
+ "ephHandle does not point to TPM_KEY_AUTHCHANGE\n");
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_RSAPrivateDecryptMalloc(&a1Auth, /* decrypted data */
+ &a1AuthLength, /* actual size of decrypted data */
+ encNewAuth.buffer, /* encrypted data */
+ encNewAuth.size, /* encrypted data size */
+ ephKey);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ stream = a1Auth;
+ stream_size = a1AuthLength;
+ returnCode = TPM_ChangeauthValidate_Load(&changeauthValidate, &stream, &stream_size);
+ }
+ /* 5. The TPM SHALL create b1 by performing the following HMAC calculation: b1 = HMAC (a1 ->
+ newAuthSecret). The secret for this calculation is encData -> currentAuth. This means that b1
+ is a value built from the current AuthData value (encData -> currentAuth) and the new
+ AuthData value (a1 -> newAuthSecret). */
+ /* 6. The TPM SHALL compare b1 with newAuthLink. The TPM SHALL indicate a failure if the values
+ do not match. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_Check(&valid,
+ newAuthLink, /* expect */
+ keyEntity.usageAuth, /* HMAC key is current auth */
+ TPM_SECRET_SIZE, changeauthValidate.newAuthSecret,
+ 0, NULL);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (!valid) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Error, authenticating newAuthLink\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 7. The TPM SHALL replace e1 -> authData with a1 -> newAuthSecret */
+ TPM_Secret_Copy(keyEntity.usageAuth, changeauthValidate.newAuthSecret);
+ /* 8. The TPM SHALL encrypt e1 using the appropriate functions for the entity type. The key
+ to encrypt with is parentHandle. */
+ returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey);
+ }
+ /* 9. The TPM SHALL create salt-Nonce by taking the next 20 bytes from the TPM RNG. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Random(saltNonce, TPM_NONCE_SIZE);
+ }
+ /* 10. The TPM SHALL create changeProof a HMAC of (saltNonce concatenated with a1 -> n1) using
+ a1 -> newAuthSecret as the HMAC secret. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_HMAC_Generate(changeProof, /* hmac output */
+ changeauthValidate.newAuthSecret, /* hmac key */
+ TPM_NONCE_SIZE, saltNonce,
+ TPM_NONCE_SIZE, changeauthValidate.n1,
+ 0, NULL);
+ }
+ /* 11. The TPM MUST destroy the TPM_KEY_AUTHCHANGE key associated with the authorization
+ session. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Deleting ephemeral key\n");
+ TPM_Key_Delete(ephKey); /* free the key resources */
+ free(ephKey); /* free the key itself */
+ /* remove entry from the key handle entries list */
+ returnCode = TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries,
+ ephHandle);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ChangeAuthAsymFinish: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return outData */
+ returnCode = TPM_SizedBuffer_Store(response, &outData);
+ }
+ /* return saltNonce */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Store(response, saltNonce);
+ }
+ /* return changeProof */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Store(response, changeProof);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&encNewAuth); /* @1 */
+ TPM_SizedBuffer_Delete(&encData); /* @2 */
+ TPM_SizedBuffer_Delete(&outData); /* @3 */
+ TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */
+ free(e1DecryptData); /* @5 */
+ free(a1Auth); /* @6 */
+ TPM_ChangeauthValidate_Delete(&changeauthValidate); /* @7 */
+ return rcf;
+}
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, &paramSize);
+ }
+ /* get label */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Loadn(label, TPM_COUNTER_LABEL_SIZE, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_CreateCounter: label", label);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_CreateCounter: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Using the authHandle field, validate the owner's AuthData to execute the command and all
+ of the incoming parameters. The authorization session MUST be OSAP or DSAP. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_OSAP,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ NULL,
+ tpm_state->tpm_permanent_data.ownerAuth);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 2. Ignore continueAuthSession on input and set continueAuthSession to FALSE on output */
+ if (returnCode == TPM_SUCCESS) {
+ continueAuthSession = FALSE;
+ }
+ /* 3. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(a1Auth,
+ NULL,
+ encAuth,
+ auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* even and odd */
+ }
+ /* 4. Validate that there is sufficient internal space in the TPM to create a new counter. If
+ there is insufficient space the command returns an error. */
+ /* a. The TPM MUST provide storage for a1, TPM_COUNTER_VALUE, countID, and any other internal
+ data the TPM needs to associate with the counter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Counters_GetNewHandle(&counterValue, /* structure */
+ &countID, /* index */
+ tpm_state->tpm_permanent_data.monotonicCounter);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ writeAllNV = TRUE;
+ /* 5. Increment the max counter value */
+ TPM_Counters_GetNextCount(&nextCount,
+ tpm_state->tpm_permanent_data.monotonicCounter);
+ /* 6. Set the counter to the max counter value */
+ /* 7. Set the counter label to label */
+ returnCode = TPM_CounterValue_Set(counterValue,
+ countID,
+ label,
+ nextCount,
+ a1Auth);
+ /* 8. Create a countID */
+ /* NOTE Done in TPM_Counters_GetNewHandle() */
+ }
+ /* save the permanent data structure in NVRAM */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_CreateCounter: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return the countID */
+ returnCode = TPM_Sbuffer_Append32(response, countID);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* Return the TPM_COUNTER_VALUE publicly visible members */
+ returnCode = TPM_CounterValue_StorePublic(response, counterValue);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 25.2 TPM_IncrementCounter rev 87
+
+ This authorized command increments the indicated counter by one. Once a counter has been
+ incremented then all subsequent increments must be for the same handle until a successful
+ TPM_Startup(ST_CLEAR) is executed.
+
+ The order for checking validation of the command parameters when no counter is active, keeps an
+ attacker from creating a denial-of-service attack.
+
+ This function increments the counter by 1.
+ The TPM MAY implement increment throttling to avoid burn problems
+*/
+
+TPM_RESULT TPM_Process_IncrementCounter(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_COUNT_ID countID; /* The handle of a valid counter */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for counter
+ authorization */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization
+ session handle */
+ TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use
+ of countID. HMAC key: countID -> authData */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_SECRET *hmacKey;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_COUNTER_VALUE *counterValue = NULL; /* The counter value */
+
+ printf("TPM_Process_IncrementCounter: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&countID, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_IncrementCounter: countID %u\n", countID);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ counterAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_IncrementCounter: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* The first check is that either there is no active counter and the countID has been created
+ or that the countID is the active counter */
+ if (returnCode == TPM_SUCCESS) {
+ /* 1. If TPM_STCLEAR_DATA -> countID is NULL */
+ if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) {
+ /* a. Validate that countID is a valid counter, return TPM_BAD_COUNTER on mismatch */
+ returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter,
+ countID);
+ }
+ /* 2. else (TPM_STCLEAR_DATA -> countID is not NULL */
+ else {
+ /* a. If TPM_STCLEAR_DATA -> countID does not equal countID */
+ if (tpm_state->tpm_stclear_data.countID != countID) {
+ if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_ILLEGAL) {
+ printf("TPM_Process_IncrementCounter: Error, counter has been released\n");
+ }
+ else {
+ printf("TPM_Process_IncrementCounter: Error, %u is already active\n",
+ tpm_state->tpm_stclear_data.countID);
+ }
+ /* i. Return TPM_BAD_COUNTER */
+ returnCode = TPM_BAD_COUNTER;
+ }
+ }
+ }
+ /* b. Validate the command parameters using counterAuth */
+ /* Get the TPM_COUNTER_VALUE associated with the countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Counters_GetCounterValue(&counterValue,
+ tpm_state->tpm_permanent_data.monotonicCounter,
+ countID);
+ }
+ /* get the session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_COUNTER,
+ ordinal,
+ NULL,
+ &(counterValue->authData), /* OIAP */
+ counterValue->digest); /* OSAP */
+ }
+ /* Validate the authorization to use the key pointed to by keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ counterAuth); /* Authorization digest for input */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 1. If TPM_STCLEAR_DATA -> countID is NULL */
+ if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) {
+ /* c. Set TPM_STCLEAR_DATA -> countID to countID */
+ tpm_state->tpm_stclear_data.countID = countID;
+ printf("TPM_Process_IncrementCounter: Setting %u as active counter\n", countID);
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* 3. Increments the counter by 1 */
+ counterValue->counter++; /* in TPM_PERMANENT_DATA */
+ /* save the permanent data structure in NVRAM */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ TRUE,
+ returnCode);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_IncrementCounter: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 4. Return new count value in count */
+ returnCode = TPM_CounterValue_StorePublic(response, counterValue);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* owner HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 25.3 TPM_ReadCounter rev 87
+
+ Reading the counter provides the caller with the current number in the sequence.
+
+ This returns the current value for the counter indicated. The counter MAY be any valid counter.
+*/
+
+TPM_RESULT TPM_Process_ReadCounter(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_COUNT_ID countID; /* ID value of the counter */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_ReadCounter: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&countID, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ReadCounter: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Validate that countID points to a valid counter. Return TPM_BAD_COUNTER on error. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReadCounter: countID %u\n", countID);
+ returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter,
+ countID);
+ }
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ReadCounter: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* 2. Return count (directly from TPM_PERMANENT_DATA) */
+ returnCode = TPM_CounterValue_StorePublic
+ (response, &(tpm_state->tpm_permanent_data.monotonicCounter[countID]));
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 25.4 TPM_ReleaseCounter rev 87
+
+ This command releases a counter such that no reads or increments of the indicated counter will
+ succeed.
+
+ The TPM uses countID to locate a valid counter.
+*/
+
+TPM_RESULT TPM_Process_ReleaseCounter(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_COUNT_ID countID; /* ID value of the counter */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for countID
+ authorization */
+ TPM_NONCE nonceOdd; /* Nonce associated with countID */
+ TPM_BOOL continueAuthSession = TRUE; /* Ignored */
+ TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use
+ of countID. HMAC key: countID -> authData */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus = FALSE; /* audit the ordinal */
+ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport
+ session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_SECRET *hmacKey;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_COUNTER_VALUE *counterValue; /* associated with countID */
+ TPM_SECRET savedAuth; /* saved copy for response */
+ TPM_BOOL writeAllNV = FALSE; /* flag to write back NV*/
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_ReleaseCounter: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&countID, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReleaseCounter: countID %u\n", countID);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ counterAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ReleaseCounter: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Authenticate the command and the parameters using the AuthData pointed to by
+ countID. Return TPM_AUTHFAIL on error */
+ /* Get the TPM_COUNTER_VALUE associated with the countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Counters_GetCounterValue(&counterValue,
+ tpm_state->tpm_permanent_data.monotonicCounter,
+ countID);
+ }
+ /* get the session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_COUNTER,
+ ordinal,
+ NULL,
+ &(counterValue->authData), /* OIAP */
+ counterValue->digest); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* make a copy of the HMAC key for the response, since it gets invalidated */
+ TPM_Secret_Copy(savedAuth, *hmacKey);
+ /* Validate the authorization to use the key pointed to by countID */
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ counterAuth); /* Authorization digest for input */
+ }
+ /* 3. The TPM invalidates sessions */
+ /* a. MUST invalidate all OSAP sessions associated with the counter */
+ /* b. MAY invalidate any other session */
+ /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_AuthSessions_TerminateEntity(&continueAuthSession,
+ authHandle,
+ tpm_state->tpm_stclear_data.authSessions,
+ TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */
+ &(counterValue->digest)); /* entityDigest */
+ }
+ /* 2. The TPM invalidates all internal information regarding the counter. This includes
+ releasing countID such that any subsequent attempts to use countID will fail. */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReleaseCounter: Releasing counter %u\n", countID);
+ returnCode = TPM_CounterValue_Release(counterValue, countID);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ writeAllNV= TRUE;
+ /* 4. If TPM_STCLEAR_DATA -> countID equals countID, */
+ if (tpm_state->tpm_stclear_data.countID == countID ) {
+ printf("TPM_Process_ReleaseCounter: Deactivating counter %u\n", countID);
+ /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the NULL value) */
+ tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL;
+ }
+ }
+ /* save the permanent data structure in NVRAM */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ReleaseCounter: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ savedAuth, /* saved countID HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, terminate the session. */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
+
+/* 25.5 TPM_ReleaseCounterOwner rev 101
+
+ This command releases a counter such that no reads or increments of the indicated counter will
+ succeed.
+
+ This invalidates all information regarding a counter.
+*/
+
+TPM_RESULT TPM_Process_ReleaseCounterOwner(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ TPM_COUNT_ID countID; /* ID value of the counter */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner
+ authentication */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization
+ session handle */
+ TPM_AUTHDATA ownerAuth; /* The authorization session digest that authorizes the
+ inputs. HMAC key: ownerAuth */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus = FALSE; /* audit the ordinal */
+ TPM_BOOL transportEncrypt = TRUE; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_SECRET *hmacKey = NULL;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_COUNTER_VALUE *counterValue; /* associated with countID */
+ TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_ReleaseCounterOwner: Ordinal Entry\n");
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&countID, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_ReleaseCounterOwner: countID %u\n", countID);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_ReleaseCounterOwner: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Validate that ownerAuth properly authorizes the command and parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 2. The TPM uses countID to locate a valid counter. Return TPM_BAD_COUNTER if not found. */
+ /* Get the TPM_COUNTER_VALUE associated with the countID */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Counters_GetCounterValue(&counterValue,
+ tpm_state->tpm_permanent_data.monotonicCounter,
+ countID);
+ }
+ /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_AuthSessions_TerminateEntity(&continueAuthSession,
+ authHandle,
+ tpm_state->tpm_stclear_data.authSessions,
+ TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */
+ &(counterValue->digest)); /* entityDigest */
+ }
+ /* 3. The TPM invalidates all internal information regarding the counter. This includes
+ releasing countID such that any subsequent attempts to use countID will fail. */
+ /* NOTE: This function can only return a TPM_FAIL error, so that the failure to store
+ TPM_PERMANENT_DATA will already be reported as fatal. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CounterValue_Release(counterValue, countID);
+ }
+ /* 4. The TPM invalidates sessions */
+ /* a. MUST invalidate all OSAP sessions associated with the counter */
+ /* b. MAY invalidate any other session */
+ if (returnCode == TPM_SUCCESS) {
+ writeAllNV = TRUE;
+ /* 5. If TPM_STCLEAR_DATA -> countID equals countID, */
+ if (tpm_state->tpm_stclear_data.countID == countID ) {
+ printf("TPM_Process_ReleaseCounterOwner: Deactivating counter %u\n", countID);
+ /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the zero value) */
+ tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL;
+ }
+ }
+ /* save the permanent data structure in NVRAM */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_ReleaseCounterOwner: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, terminate the session. */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ return rcf;
+}
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, &paramSize);
+ }
+ /* 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, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* get hashData */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum);
+ returnCode = TPM_SizedBuffer_Load(&hashData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* get keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle);
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get certHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_Load32(&certHandle, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get the antiReplay parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ 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(&dividend,
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get inputData1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inputData1, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get inputData1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inputData1, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get opCode parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: familyID %08x\n", familyID);
+ returnCode = TPM_Load32(&opCode, &command, &paramSize);
+ }
+ /* get opData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: opCode %u\n", opCode);
+ returnCode = TPM_SizedBuffer_Load(&opData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get delAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Load(delAuth, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get publicInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: increment %02x\n", increment);
+ returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, &paramSize);
+ }
+ /* get delAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Load(delAuth, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get blobSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: index %u\n", index);
+ returnCode = TPM_Load32(&blobSize, &command, &paramSize);
+ }
+ /* get blob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateOwnerBlob_Load(&d1Blob, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ /* get labelPrivCADigest parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(labelPrivCADigest, &command, &paramSize);
+ }
+ /* get idKeyParams parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_Load(&idKeyParams, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ 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, &paramSize);
+ }
+ 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,
+ &current,
+ 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,
+ &current,
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get keyInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_Load(&keyInfo, &command, &paramSize); /* freed @1 */
+ }
+ /* get generateReset parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadBool(&generateReset, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get keyInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyParms_Load(&keyInfo, &command, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get pubKey parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Pubkey_Load(&pubKey, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get migrationKeyAuth */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, &paramSize);
+ }
+ /* get encData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get random */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&random, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ parentAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get migrationKey */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Pubkey_Load(&migrationKey, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get encData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&maAuthHandle,
+ &maAuthHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ keyAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get keyInfo */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_Load(&keyInfo, &command, &paramSize);
+ }
+ /* get migrationAuthorityApproval */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(migrationAuthorityApproval, &command, &paramSize);
+ }
+ /* get migrationAuthorityDigest */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(migrationAuthorityDigest, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ pubAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get signedData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(signedData, &command, &paramSize);
+ }
+ /* get signatureValue */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&signatureValue, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ pubAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get migrationType */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load16(&migrationType, &command, &paramSize);
+ }
+ /* get migrationKeyAuth */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, &paramSize);
+ }
+ /* get pubSourceKeyDigest */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(pubSourceKeyDigest, &command, &paramSize);
+ }
+ /* get msaListBuffer */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get sigTicket */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&sigTicketBuffer, &command, &paramSize);
+ }
+ /* get encData */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&parentAuthHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ parentAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get sigTicket */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(sigTicket, &command, &paramSize);
+ }
+ /* get migratedKey */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_Load(&migratedKey, &command, &paramSize);
+ }
+ /* get msaListBuffer */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, &paramSize);
+ }
+ /* get random */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&random, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ parentAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get offset parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&offset, &command, &paramSize);
+ }
+ /* get dataSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&dataSize, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get offset parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&offset, &command, &paramSize);
+ }
+ /* get dataSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&dataSize, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ authHmac,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&offset, &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&data, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get offset parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&offset, &command, &paramSize);
+ }
+ /* get data parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&data, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ authValue,
+ &command, &paramSize);
+ }
+ 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, &paramSize,
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER | 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get newContents parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DirWriteAuth: dirIndex %08x\n", dirIndex);
+ returnCode = TPM_Digest_Load(newContents, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get encOwnerAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_TakeOwnership: protocolID %04hx\n", protocolID);
+ returnCode = TPM_SizedBuffer_Load(&encOwnerAuth, &command, &paramSize);
+ }
+ /* get encSrkAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&encSrkAuth, &command, &paramSize);
+ }
+ /* get srkParams parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_Load(&srkParams, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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,
+ &current,
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get targetPCR parameter */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_Quote: externalData", externalData);
+ returnCode = TPM_PCRSelection_Load(&targetPCR, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get targetPCR parameter */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_Quote2: externalData", externalData);
+ returnCode = TPM_PCRSelection_Load(&targetPCR, &command, &paramSize);
+ }
+ /* get addVersion parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadBool(&addVersion, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get inDigest parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Digest_Load(inDigest, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize, 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, &paramSize, 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, &paramSize, &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, &paramSize, &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, &paramSize);
+ }
+ /* get subCap parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_GetCapability: capArea %08x\n", capArea);
+ returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get capArea parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&capArea, &command, &paramSize);
+ }
+ /* get get subCap parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get subCap parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SetCapability: capArea %08x \n", capArea);
+ returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
+ }
+ /* get setValue parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&setValue , &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get entityValue */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&entityValue, &command, &paramSize);
+ }
+ /* get nonceOddOSAP */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_OSAP: entityValue %08x\n", entityValue);
+ returnCode = TPM_Nonce_Load(nonceOddOSAP, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DSAP: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* get nonceOddDSAP */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DSAP: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_Nonce_Load(nonceOddDSAP, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* get entityValue */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SetOwnerPointer: entityType %04hx\n", entityType);
+ returnCode = TPM_Load32(&entityValue, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get label */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SaveContext: resourceType %08x\n", resourceType);
+ returnCode = TPM_Loadn(label, TPM_CONTEXT_LABEL_SIZE, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get contextSize parameter (redundant, not used) */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_LoadContext: keepHandle %02x\n", keepHandle);
+ returnCode = TPM_Load32(&contextSize, &command, &paramSize);
+ }
+ /* get contextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&b1ContextBlob, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_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,
+ &current,
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get bitName parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&bitName, &command, &paramSize);
+ }
+ /* get bitValue parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load8(&bitValue, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get keyContextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&keyContextBlob, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get authContextBlob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_ContextBlob_Load(&authContextBlob, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get pcrInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, &paramSize);
+ }
+ /* get inData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inData, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get pcrInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, &paramSize);
+ }
+ /* get inData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inData, &command, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get dataMigrationAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Load(dataMigrationAuth, &command, &paramSize);
+ }
+ /* get keyInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_Load(&keyInfo, &command, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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(&currentTimeSec, &currentTimeUsec);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get digestToStamp parameter */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_TickStampBlob: antiReplay", antiReplay);
+ returnCode = TPM_Digest_Load(digestToStamp, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ 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, &paramSize);
+ }
+ 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(&currentTicks); /* 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(&currentTicksSbuffer); /* freed @8 */
+ /*
+ get inputs
+ */
+ /* get encHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&encHandle, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get secret */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_EstablishTransport: transPublic->transAttributes %08x\n",
+ transPublic.transAttributes);
+ returnCode = TPM_SizedBuffer_Load(&secret, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ keyAuth,
+ &command, &paramSize);
+ }
+ 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(&currentTicks, &(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(&currentTicksSbuffer, &currentTicks);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* get the currentTicks serialization results */
+ TPM_Sbuffer_Get(&currentTicksSbuffer, &currentTicksBuffer, &currentTicksLength);
+ 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), &currentTicks);
+ /* 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, &currentTicks);
+ }
+ 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(&currentTicksSbuffer); /* @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(&currentTicksSbuffer); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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(&currentTicks, &(tpm_state->tpm_stany_data.currentTicks.currentTicks));
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Uint64_Store(&currentTicksSbuffer,
+ &(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(&currentTicksSbuffer, &currentTicksBuffer, &currentTicksLength);
+ 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(&currentTicksSbuffer); /* @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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ 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, &paramSize);
+ }
+ 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