diff options
Diffstat (limited to 'src/tpm12/tpm_startup.c')
-rw-r--r-- | src/tpm12/tpm_startup.c | 1446 |
1 files changed, 1446 insertions, 0 deletions
diff --git a/src/tpm12/tpm_startup.c b/src/tpm12/tpm_startup.c new file mode 100644 index 0000000..25b9e08 --- /dev/null +++ b/src/tpm12/tpm_startup.c @@ -0,0 +1,1446 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Startup and State */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_startup.c 4533 2011-03-30 19:50:41Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_constants.h" +#include "tpm_commands.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_digest.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvfilename.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_session.h" + +#include "tpm_startup.h" + +/* + Save State +*/ + +/* TPM_SaveState_Load() restores the TPM state from a stream created by TPM_SaveState_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_SaveState_Load:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Load: Loading PCR's\n"); + } + /* 1. Store PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Load() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done at TPM_StclearData_Load() */ + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_SaveState_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_SaveState_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_SaveState_Store() stores the TPM state to a stream that can be restored through + TPM_SaveState_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_SaveState_Store:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Store: Storing PCR's\n"); + } + /* NOTE: Actions from TPM_SaveState */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Store() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* NOTE Done naturally because this function is called between input and output audit. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE This implementation saves all keys. Owner evict keys are not saved in the state blob, + as they are already saved in the file system */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done by TPM_StclearData_Store() */ + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_SaveState_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_SaveState_IsSaveKey() determines which keys are saved as part of the saved state. + + According to Ryan, all keys must be saved for this to be of use. +*/ + +void TPM_SaveState_IsSaveKey(TPM_BOOL *save, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + *save = FALSE; + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Owner evict keys are not saved in the state blob, as they are already saved in the file + system */ + if (!(tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + *save = TRUE; + } + else { + *save = FALSE; + } + if (*save) { + printf(" TPM_SaveState_IsSaveKey: Save key handle %08x\n", tpm_key_handle_entry->handle); + } + return; +} + +/* TPM_SaveState_NVLoad() deserializes the saved state data from the NV file TPM_SAVESTATE_NAME + + 0 on success. + Returns TPM_RETRY on non-existent file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_SaveState_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_SaveState_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + } + /* deserialize from stream */ + if (rc == 0) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_SaveState_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_SaveState_NVLoad: Error (fatal) loading deserializing saved state\n"); + rc = TPM_FAIL; + } + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVStore() serializes saved state data and stores it in the NV file + TPM_SAVESTATE_NAME +*/ + +TPM_RESULT TPM_SaveState_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_SaveState_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_SaveState_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_SaveState_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_SAVESTATE_SPACE) { + printf("TPM_SaveState_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_SAVESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + tpm_state->tpm_stany_flags.stateSaved = TRUE; /* mark the state as stored */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVDelete() deletes the NV file + + If mustExist is TRUE, returns an error if the file does not exist. + If mustExist is FALSE, returns success if the file does not exist. +*/ + +TPM_RESULT TPM_SaveState_NVDelete(tpm_state_t *tpm_state, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SaveState_NVDelete:\n"); + if (rc == 0) { + /* remove the saved state */ + rc = TPM_NVRAM_DeleteName(tpm_state->tpm_number, + TPM_SAVESTATE_NAME, + mustExist); + tpm_state->tpm_stany_flags.stateSaved = FALSE; /* mark the state as deleted */ + } + return rc; +} + +/* Volatile state includes all the tpm_state structure volatile members. It is a superset of Saved + state, used when the entire TPM state must be saved and restored +*/ + +/* TPM_VolatileAll_Load() restores the TPM state from a stream created by TPM_VolatileAll_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_VolatileAll_Load:\n"); + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_VSTATE_V1, stream, stream_size); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Load(stream, stream_size); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STCLEAR_FLAGS_V1, stream, stream_size); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Load(&(tpm_state->tpm_stany_flags), stream, stream_size); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Load(&(tpm_state->tpm_stany_data), stream, stream_size); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading SHA ordinal context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context), stream, stream_size); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading TIS context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context_tis), stream, stream_size); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->transportHandle), stream, stream_size); + } + /* testState */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->testState), stream, stream_size); + } + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_VolatileAll_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_VolatileAll_Store() stores the TPM state to a stream that can be restored through + TPM_VolatileAll_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_VolatileAll_Store:\n"); + /* overall format tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_VSTATE_V1); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Store(sbuffer); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_FLAGS_V1); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Store(sbuffer, &(tpm_state->tpm_stany_flags)); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Store(sbuffer, &(tpm_state->tpm_stany_data)); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing SHA ordinal context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing TIS context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context_tis); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->transportHandle); + } + /* testState */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->testState); + } + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_VolatileAll_NVLoad() deserializes the entire volatile state data from the NV file + TPM_VOLATILESTATE_NAME. + + If the file does not exist (a normal startup), returns success. + + 0 on success or non-existent file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_VolatileAll_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_VolatileAll_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + /* if the file does not exist, leave the volatile state initial values */ + if (rc == TPM_RETRY) { + done = TRUE; + rc = 0; + } + else if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading %s\n", TPM_VOLATILESTATE_NAME); + rc = TPM_FAIL; + } + } + /* deserialize from stream */ + if ((rc == 0) && !done) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_VolatileAll_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading deserializing state\n"); + rc = TPM_FAIL; + } + } + if (rc != 0) { + printf(" TPM_VolatileAll_NVLoad: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_VolatileAll_NVStore() serializes the entire volatile state data and stores it in the NV file + TPM_VOLATILESTATE_NAME +*/ + +TPM_RESULT TPM_VolatileAll_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_VolatileAll_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_VolatileAll_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_VOLATILESTATE_SPACE) { + printf("TPM_VolatileAll_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_VOLATILESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Compiled in TPM Parameters +*/ + +TPM_RESULT TPM_Parameters_Load(unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Load:\n"); + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TPM_PARAMETERS_V1, + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MAJOR, "TPM_MAJOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MINOR, "TPM_MINOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_PCCLIENT, "TPM_PCCLIENT", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_PCR, "TPM_NUM_PCR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_RSA_KEY_LENGTH_MAX, "TPM_RSA_KEY_LENGTH_MAX", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_KEY_HANDLES, "TPM_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_OWNER_EVICT_KEY_HANDLES, "TPM_OWNER_EVICT_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + "TPM_NUM_FAMILY_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, + "TPM_NUM_DELEGATE_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_AUTH_SESSIONS, "TPM_MIN_AUTH_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_TRANS_SESSIONS, "TPM_MIN_TRANS_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_DAA_SESSIONS, "TPM_MIN_DAA_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_COUNTERS, "TPM_MIN_COUNTERS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_SESSION_LIST, "TPM_MIN_SESSION_LIST", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check32(TPM_MAX_NV_SPACE, "TPM_MAX_NV_SPACE", + stream, stream_size); + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check8(uint8_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint8_t tmp8; + + if (rc == 0) { + rc = TPM_Load8(&tmp8, stream, stream_size); + if (tmp8 != expected) { + printf("TPM_Parameters_Check8: Error (fatal) %s received %u expect %u\n", + parameter, tmp8, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check16(uint16_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t tmp16; + + if (rc == 0) { + rc = TPM_Load16(&tmp16, stream, stream_size); + if (tmp16 != expected) { + printf("TPM_Parameters_Check16: Error (fatal) %s received %u expect %u\n", + parameter, tmp16, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check32(uint32_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t tmp32; + + if (rc == 0) { + rc = TPM_Load32(&tmp32, stream, stream_size); + if (tmp32 != expected) { + printf("TPM_Parameters_Check32: Error (fatal) %s received %u expect %u\n", + parameter, tmp32, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Store(TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TPM_PARAMETERS_V1); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MAJOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MINOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_PCCLIENT); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_PCR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_RSA_KEY_LENGTH_MAX); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_OWNER_EVICT_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_AUTH_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_TRANS_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_DAA_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_COUNTERS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_SESSION_LIST); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, TPM_MAX_NV_SPACE); + } + return rc; +} + + +/* 27.5 TPM_Reset rev 105 + + Releases all resources associated with existing authorization sessions. This is useful if a TSS + driver has lost track of the state in the TPM. + + This is a deprecated command in V1.2. This command in 1.1 only referenced authorization sessions + and is not upgraded to affect any other TPM entity in 1.2 +*/ + +TPM_RESULT TPM_Process_Reset(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Reset: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Reset: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM invalidates all resources allocated to authorization sessions as per version 1.1 + extant in the TPM */ + /* a. This includes structures created by TPM_SaveAuthContext and TPM_SaveKeyContext */ + /* b.The TPM MUST invalidate OSAP sessions */ + /* c.The TPM MAY invalidate DSAP sessions */ + /* d. The TPM MUST NOT invalidate structures created by TPM_SaveContext */ + if (returnCode == TPM_SUCCESS) { + TPM_StclearData_AuthSessionDelete(&(tpm_state->tpm_stclear_data)); + } + /* 2. The TPM does not reset any PCR or DIR values. */ + /* 3. The TPM does not reset any flags in the TPM_STCLEAR_FLAGS structure. */ + /* 4. The TPM does not reset or invalidate any keys */ + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Reset: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 3.2 TPM_Startup rev 101 + + TPM_Startup is always preceded by TPM_Init, which is the physical indication (a system-wide + reset) that TPM initialization is necessary. + + There are many events on a platform that can cause a reset and the response to these events can + require different operations to occur on the TPM. The mere reset indication does not contain + sufficient information to inform the TPM as to what type of reset is occurring. Additional + information known by the platform initialization code needs transmitting to the TPM. The + TPM_Startup command provides the mechanism to transmit the information. + + The TPM can startup in three different modes: + + A "clear" start where all variables go back to their default or non-volatile set state + + A "save" start where the TPM recovers appropriate information and restores various values based + on a prior TPM_SaveState. This recovery requires an invocation of TPM_Init to be successful. + + A failing "save" start must shut down the TPM. The CRTM cannot leave the TPM in a state where an + untrusted upper software layer could issue a "clear" and then extend PCR's and thus mimic the + CRTM. + + A "deactivated" start where the TPM turns itself off and requires another TPM_Init before the TPM + will execute in a fully operational state. The TPM can startup in three different modes: +*/ + +TPM_RESULT TPM_Process_Startup(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + TPM_RESULT returnCode1 = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_STARTUP_TYPE startupType; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Startup: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get startupType parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&startupType, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Startup: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* TPM_CheckState() can check for the normal case where postInitialise TRUE is an error. This + is the only command where FALSE is the error. */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STANY_FLAGS -> postInitialise is FALSE, */ + if (!(tpm_state->tpm_stany_flags.postInitialise)) { + /* a. Then the TPM MUST return TPM_INVALID_POSTINIT, and exit this capability */ + printf("TPM_Process_Startup: Error, postInitialise is FALSE\n"); + returnCode = TPM_INVALID_POSTINIT; + } + } + if (returnCode == TPM_SUCCESS) { + /* 1. If the TPM is in failure mode */ + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + /* a. TPM_STANY_FLAGS -> postInitialize is still set to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + printf("TPM_Process_Startup: Error, shutdown is TRUE\n"); + /* b. The TPM returns TPM_FAILEDSELFTEST */ + returnCode = TPM_FAILEDSELFTEST; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + switch (startupType) { + case TPM_ST_CLEAR: /* The TPM is starting up from a clean state */ + returnCode = TPM_Startup_Clear(tpm_state); + break; + case TPM_ST_STATE: /* The TPM is starting up from a saved state */ + returnCode = TPM_Startup_State(tpm_state); + break; + case TPM_ST_DEACTIVATED: /* The TPM is to startup and set the deactivated flag to + TRUE */ + returnCode = TPM_Startup_Deactivated(tpm_state); + break; + default: + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + if (returnCode == TPM_SUCCESS) { + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + } + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode1 = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not + exist. */ + if (returnCode == TPM_SUCCESS) { /* previous error takes precedence */ + returnCode = returnCode1; + } + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Startup: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 3.2 TPM_Startup(TPM_ST_CLEAR) rev 99 +*/ + +TPM_RESULT TPM_Startup_Clear(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Clear:\n"); + /* 2. If stType = TPM_ST_CLEAR */ + if (returnCode == TPM_SUCCESS) { + /* a. Ensure that sessions associated with resources TPM_RT_CONTEXT, TPM_RT_AUTH, + TPM_RT_DAA_TPM, and TPM_RT_TRANS are invalidated */ + /* NOTE TPM_RT_CONTEXT - + contextNonceKey cleared by TPM_Global_Init() -> TPM_StanyData_Init() + contextNonceSession cleared by TPM_Global_Init() -> TPM_StanyData_Init() + */ + /* NOTE TPM_RT_AUTH - TPM_AuthSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init() */ + /* TPM_RT_TRANS - TPM_TransportSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* TPM_RT_DAA_TPM - TPM_DaaSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* b. Reset PCR values to each correct default value */ + /* i. pcrReset is FALSE, set to 0x00..00 */ + /* ii. pcrReset is TRUE, set to 0xFF..FF */ + /* NOTE done by TPM_MainInit() -> TPM_Global_Init() */ + /* c. Set the following TPM_STCLEAR_FLAGS to their default state + i. PhysicalPresence + ii. PhysicalPresenceLock + iii. disableForceClear + */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* d. The TPM MAY initialize auditDigest to all zeros + i. If not initialized to all zeros the TPM SHALL ensure that auditDigest contains a valid + value + ii. If initialization fails the TPM SHALL set auditDigest to all zeros and SHALL set the + internal TPM state so that the TPM returns TPM_FAILEDSELFTEST to all subsequent + commands. + */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* e. The TPM SHALL set TPM_STCLEAR_FLAGS -> deactivated to the same state as + TPM_PERMANENT_FLAGS -> deactivated + */ + tpm_state->tpm_stclear_flags.deactivated = tpm_state->tpm_permanent_flags.deactivated; + /* f. The TPM MUST set the TPM_STANY_DATA fields to: */ + /* i. TPM_STANY_DATA->contextNonceSession is set to all zeros */ + /* ii. TPM_STANY_DATA->contextCount is set to 0 */ + /* iii. TPM_STANY_DATA->contextList is set to 0 */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* g. The TPM MUST set TPM_STCLEAR_DATA fields to: */ + /* i. Invalidate contextNonceKey */ + /* ii. countID to zero */ + /* iii. OwnerReference to TPM_KH_OWNER */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearData_Init() */ + /* h. The TPM MUST set the following TPM_STCLEAR_FLAGS to */ + /* i. bGlobalLock to FALSE */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* i. Determine which keys should remain in the TPM */ + /* i. For each key that has a valid preserved value in the TPM */ + /* (1) if parentPCRStatus is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* (2) if isVolatile is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* NOTE Since TPM_Global_Init() calls TPM_KeyHandleEntries_Init(), there are no keys + remaining. Since this TPM implementation loads keys into volatile memory, not NVRAM, no + keys are preserved at ST_CLEAR. */ + /* ii. Keys under control of the OwnerEvict flag MUST stay resident in the TPM */ + /* NOTE Done by TPM_PermanentAll_NVLoad() */ + /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at + TPM_Startup(ST_Clear) */ + TPM_NVIndexEntries_StClear(&(tpm_state->tpm_nv_index_entries)); + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_STATE) rev 100 + */ + +TPM_RESULT TPM_Startup_State(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_State:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. If the TPM has no state to restore the TPM MUST set the internal state such that it + returns TPM_FAILEDSELFTEST to all subsequent commands */ + /* b. The TPM MAY determine for each session type (authorization, transport, DAA, ...) to + release or maintain the session information. The TPM reports how it manages sessions in + the TPM_GetCapability command. */ + /* c. The TPM SHALL take all necessary actions to ensure that all PCRs contain valid + preserved values. If the TPM is unable to successfully complete these actions, it SHALL + enter the TPM failure mode. */ + /* i. For resettable PCR the TPM MUST set the value of TPM_STCLEAR_DATA -> PCR[] to the + resettable PCR default value. The TPM MUST NOT restore a resettable PCR to a preserved + value */ + /* d. The TPM MAY initialize auditDigest to all zeros */ + /* i. Otherwise, the TPM SHALL take all actions necessary to ensure that auditDigest + contains a valid value. If the TPM is unable to successfully complete these actions, the + TPM SHALL initialize auditDigest to all zeros and SHALL set the internal state such that + the TPM returns TPM_FAILEDSELFTEST to all subsequent commands. */ + /* e. The TPM MUST restore the following flags to their preserved states: */ + /* i. All values in TPM_STCLEAR_FLAGS */ + /* ii. All values in TPM_STCLEAR_DATA */ + /* f. The TPM MUST restore all keys that have a valid preserved value */ + /* NOTE Owner evict keys are loaded at TPM_PermanentAll_NVLoad() */ + returnCode = TPM_SaveState_NVLoad(tpm_state); /* returns TPM_RETRY on non-existent file */ + } + /* g. The TPM resumes normal operation. If the TPM is unable to resume normal operation, it + SHALL enter the TPM failure mode. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Startup_State: Error restoring state\n"); + returnCode = TPM_FAILEDSELFTEST; + printf(" TPM_Startup_State: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_DEACTIVATED) rev 97 + */ + +TPM_RESULT TPM_Startup_Deactivated(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Deactivated:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Invalidate sessions */ + /* i. Ensure that all resources associated with saved and active sessions are invalidated */ + /* NOTE Done at TPM_MainInit() */ + /* b. The TPM MUST set TPM_STCLEAR_FLAGS -> deactivated to TRUE */ + tpm_state->tpm_stclear_flags.deactivated = TRUE; + } + return returnCode; +} + +#if 0 +/* TPM_Startup_Any() rev 96 + + Handles Actions common to all TPM_Startup options. +*/ + +TPM_RESULT TPM_Startup_Any(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Any:\n"); + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not exist. */ + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + return returnCode; +} +#endif + +/* 3.3 TPM_SaveState rev 111 + + This warns a TPM to save some state information. + + If the relevant shielded storage is non-volatile, this command need have no effect. + + If the relevant shielded storage is volatile and the TPM alone is unable to detect the loss of + external power in time to move data to non-volatile memory, this command should be presented + before the TPM enters a low or no power state. + + Resettable PCRs are tied to platform state that does not survive a sleep state. If the PCRs did + not reset, they would falsely indicate that the platform state was already present when it came + out of sleep. Since some setup is required first, there would be a gap where PCRs indicated the + wrong state. Therefore, the PCRs must be recreated. +*/ + +TPM_RESULT TPM_Process_SaveState(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveState: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveState: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Preserved values MUST be non-volatile. */ + /* 2. If data is never stored in a volatile medium, that data MAY be used as preserved data. In + such cases, no explicit action may be required to preserve that data. */ + /* 3. If an explicit action is required to preserve data, it MUST be possible for the TPM to + determine whether preserved data is valid. */ + /* 4. If the parameter mirrored by a preserved value is altered, all preserved values MUST be + declared invalid. */ + if (returnCode == TPM_SUCCESS) { + /* Determine if TPM_SaveState was called from within a transport session. The TPM MAY save + transport sessions as part of the saved state. Since this TPM implements that option, + there's no point in saving the state, because it would be immediately invalidated during + the transport response. Return an error to indicate that the state was not saved. */ + if (transportInternal != NULL) { + printf("TPM_Process_SaveState: Error, called from transport session\n"); + returnCode = TPM_NO_WRAP_TRANSPORT; + } + } + /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and + the audit occurs before the state is saved. If an error occurs while or after the state is + saved, the audit still occurs. + */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* 5. The TPM MAY declare all preserved value is invalid in response to any command other that + TPM_Init. */ + /* NOTE Done by TPM_GetInParamDigest(), which is called by all ordinals */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved */ + /* 8. The contents of sessions (authorization, transport, DAA etc.) MAY be preserved as reported + by TPM_GetCapability */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SaveState_NVStore(tpm_state); + } + /* store the state in NVRAM */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveState: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* Special case, no output parameter audit */ + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} |