diff options
Diffstat (limited to '')
-rw-r--r-- | src/tpm12/tpm_key.c | 5529 |
1 files changed, 5529 insertions, 0 deletions
diff --git a/src/tpm12/tpm_key.c b/src/tpm12/tpm_key.c new file mode 100644 index 0000000..6fce495 --- /dev/null +++ b/src/tpm12/tpm_key.c @@ -0,0 +1,5529 @@ +/********************************************************************************/ +/* */ +/* Key Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_key.c 4655 2011-12-21 21:03:15Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "tpm_auth.h" +#include "tpm_commands.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvram.h" +#include "tpm_owner.h" +#include "tpm_pcr.h" +#include "tpm_sizedbuffer.h" +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_startup.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_ver.h" + +#include "tpm_key.h" + +/* The default RSA exponent */ +unsigned char tpm_default_rsa_exponent[] = {0x01, 0x00, 0x01}; + +/* local prototypes */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12); + +/* + TPM_KEY, TPM_KEY12 + + These functions generally handle either a TPM_KEY or TPM_KEY12. Where structure members differ, + the function checks the version or tag and adapts the processing to the structure type. This + handling is opaque to the caller. +*/ + + +/* TPM_Key_Init initializes a key structure. The default is TPM_KEY. Typically, a TPM_Key_Set() or + TPM_Key_Load() will adjust to TPM_KEY or TPM_KEY12 */ + +void TPM_Key_Init(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_Init:\n"); + TPM_StructVer_Init(&(tpm_key->ver)); + tpm_key->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_key->keyFlags = 0; + tpm_key->authDataUsage = 0; + TPM_KeyParms_Init(&(tpm_key->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_key->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_key->pubKey)); + TPM_SizedBuffer_Init(&(tpm_key->encData)); + tpm_key->tpm_pcr_info = NULL; + tpm_key->tpm_pcr_info_long = NULL; + tpm_key->tpm_store_asymkey = NULL; + tpm_key->tpm_migrate_asymkey = NULL; + return; +} + +/* TPM_Key_InitTag12() alters the tag and fill from TPM_KEY to TPM_KEY12 */ + +void TPM_Key_InitTag12(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_InitTag12:\n"); + ((TPM_KEY12 *)tpm_key)->tag = TPM_TAG_KEY12; + ((TPM_KEY12 *)tpm_key)->fill = 0x0000; + return; +} + +/* TPM_Key_Set() sets a TPM_KEY structure to the specified values. + + The tpm_pcr_info digestAtCreation is calculated. + + It serializes the tpm_pcr_info or tpm_pcr_info_long cache to pcrInfo. One or the other may be + specified, but not both. The tag/version is set correctly. + + If the parent_key is NULL, encData is set to the clear text serialization of the + tpm_store_asymkey member. + + If parent_key is not NULL, encData is not set yet, since further processing may be done before + encryption. + + Must call TPM_Key_Delete() to free + */ + +TPM_RESULT TPM_Key_Set(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* points to the TPM PCR array */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* must copy */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long, /* must copy */ + uint32_t keyLength, /* public key length in bytes */ + BYTE* publicKey, /* public key byte array */ + TPM_STORE_ASYMKEY *tpm_store_asymkey, /* cache TPM_STORE_ASYMKEY */ + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) /* cache TPM_MIGRATE_ASYMKEY */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + + printf(" TPM_Key_Set:\n"); + TPM_Sbuffer_Init(&sbuffer); + /* version must be TPM_KEY or TPM_KEY12 */ + if (rc == 0) { + if ((ver != 1) && (ver != 2)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY version %d is not 1 or 2\n", ver); + rc = TPM_FAIL; /* should never occur */ + } + } + /* either tpm_pcr_info != NULL for TPM_KEY or tpm_pcr_info_long != NULL for TPM_KEY12, but not + both */ + if (rc == 0) { + if ((ver == 1) && (tpm_pcr_info_long != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY and TPM_PCR_INFO_LONG both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + if ((ver == 2) && (tpm_pcr_info != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY12 and TPM_PCR_INFO both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + TPM_Key_Init(tpm_key); + if (ver == 2) { + TPM_Key_InitTag12(tpm_key); /* change tag to TPM_KEY12 */ + } + tpm_key->keyUsage = keyUsage; + tpm_key->keyFlags = keyFlags; + tpm_key->authDataUsage = authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key->algorithmParms), /* freed by caller */ + tpm_key_parms); + } + /* The pcrInfo serialization is deferred, since PCR data is be altered after the initial + 'set'. */ + if (rc == 0) { + /* generate the TPM_PCR_INFO member cache, directly copying from the tpm_pcr_info */ + if (tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key->tpm_pcr_info), tpm_pcr_info); + } + /* generate the TPM_PCR_INFO_LONG member cache, directly copying from the + tpm_pcr_info_long */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key->tpm_pcr_info_long), + tpm_pcr_info_long); + } + } + if (rc == 0) { + /* if there are PCR's specified, set the digestAtCreation */ + if (tpm_pcr_info != NULL) { + rc = TPM_PCRInfo_SetDigestAtCreation(tpm_key->tpm_pcr_info, tpm_pcrs); + } + /* if there are PCR's specified, set the localityAtCreation, digestAtCreation */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + if (rc == 0) { + rc = TPM_Locality_Set(&(tpm_key->tpm_pcr_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + rc = TPM_PCRInfoLong_SetDigestAtCreation(tpm_key->tpm_pcr_info_long, tpm_pcrs); + } + } + } + /* set TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->pubKey), + keyLength, /* in bytes */ + publicKey); + } + if (rc == 0) { + if (tpm_store_asymkey == NULL) { + printf("TPM_Key_Set: Error (fatal), No TPM_STORE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* sanity check, currently no need to set TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + if (tpm_migrate_asymkey != NULL) { + printf("TPM_Key_Set: Error (fatal), TPM_MIGRATE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* root key, no parent, just serialize the TPM_STORE_ASYMKEY structure */ + if (parent_key == NULL) { + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(&(tpm_key->encData), &sbuffer); + } + } + } + if (rc == 0) { + tpm_key->tpm_store_asymkey = tpm_store_asymkey; /* cache TPM_STORE_ASYMKEY */ + tpm_key->tpm_migrate_asymkey = tpm_migrate_asymkey; /* cache TPM_MIGRATE_ASYMKEY */ + } + /* Generate the TPM_STORE_ASYMKEY -> pubDataDigest. Serializes pcrInfo as a side effect. */ + if (rc == 0) { + rc = TPM_Key_GeneratePubDataDigest(tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_Copy() copies the source TPM_KEY to the destination. + + The destination should be initialized before the call. +*/ + +TPM_RESULT TPM_Key_Copy(TPM_KEY *tpm_key_dest, + TPM_KEY *tpm_key_src, + TPM_BOOL copyEncData) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + TPM_StructVer_Copy(&(tpm_key_dest->ver), &(tpm_key_src->ver)); /* works for TPM_KEY12 + also */ + tpm_key_dest->keyUsage = tpm_key_src->keyUsage; + tpm_key_dest->keyFlags = tpm_key_src->keyFlags; + tpm_key_dest->authDataUsage = tpm_key_src->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key_dest->algorithmParms), &(tpm_key_src->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pcrInfo), &(tpm_key_src->pcrInfo)); + } + /* copy TPM_PCR_INFO cache */ + if (rc == 0) { + if (tpm_key_src->tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key_dest->tpm_pcr_info), + tpm_key_src->tpm_pcr_info); + } + else if (tpm_key_src->tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key_dest->tpm_pcr_info_long), + tpm_key_src->tpm_pcr_info_long); + } + } + /* copy pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pubKey), &(tpm_key_src->pubKey)); + } + /* copy encData */ + if (rc == 0) { + if (copyEncData) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->encData), &(tpm_key_src->encData)); + } + } + return rc; +} + +/* TPM_Key_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + After use, call TPM_Key_Delete() to free memory +*/ + + +TPM_RESULT TPM_Key_Load(TPM_KEY *tpm_key, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Load:\n"); + /* load public data, and create PCR cache */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, FALSE, stream, stream_size); + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->encData), stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadClear() load a serialized key where the TPM_STORE_ASYMKEY structure is serialized in + clear text. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + This function is used to load internal keys (e.g. EK, SRK, owner evict keys) or keys saved as + part of a save state. +*/ + +TPM_RESULT TPM_Key_LoadClear(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + uint32_t storeAsymkeySize; + + printf(" TPM_Key_LoadClear:\n"); + /* load public data */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, isEK, stream, stream_size); + } + /* load TPM_STORE_ASYMKEY size */ + if (rc == 0) { + rc = TPM_Load32(&storeAsymkeySize, stream, stream_size); + } + /* The size might be 0 for an uninitialized internal key. That case is not an error. */ + if ((rc == 0) && (storeAsymkeySize > 0)) { + rc = TPM_Key_LoadStoreAsymKey(tpm_key, isEK, stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadPubData() deserializes a TPM_KEY or TPM_KEY12 structure, excluding encData, to + 'tpm_key'. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + If the pcrInfo stream is empty, the caches remain NULL. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_Key_Delete() to free memory +*/ + +TPM_RESULT TPM_Key_LoadPubData(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_LoadPubData:\n"); + /* peek at the first byte */ + if (rc == 0) { + /* TPM_KEY[0] is major (non zero) */ + if ((*stream)[0] != 0) { + /* load ver */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_key->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); + } + } + else { + /* TPM_KEY12 is tag (zero) */ + /* load tag */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->tag), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->fill), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + } + } + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_key->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_key->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_key->algorithmParms), stream, stream_size); + } + /* load PCRInfo */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from PCRInfo stream. If the stream is empty, a NULL is + returned. + */ + if ((rc == 0) && !isEK) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_key->tpm_pcr_info), + &(tpm_key->pcrInfo)); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromBuffer(&(tpm_key->tpm_pcr_info_long), + &(tpm_key->pcrInfo)); + } + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Key_StorePubData() serializes a TPM_KEY or TPM_KEY12 structure, excluding encData, appending + results to 'sbuffer'. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StorePubData(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubData:\n"); + + if (rc == 0) { + /* store ver */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_StructVer_Store(sbuffer, &(tpm_key->ver)); + } + else { /* TPM_KEY12 */ + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY12); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, 0x0000); + } + } + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_key->authDataUsage), sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_key->algorithmParms)); + } + /* store pcrInfo */ + if ((rc == 0) && !isEK) { + /* copy cache to pcrInfo */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { /* TPM_KEY12 */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info_long, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy pcrInfo to sbuffer */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pcrInfo)); + } + /* store pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pubKey)); + } + return rc; +} + +/* TPM_Key_Store() serializes a TPM_KEY structure, appending results to 'sbuffer' + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Store:\n"); + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, FALSE, tpm_key); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->encData)); + } + return rc; +} + +/* TPM_Key_StoreClear() serializes a TPM_KEY structure, appending results to 'sbuffer' + + TPM_Key_StoreClear() serializes the tpm_store_asymkey member as cleartext. It is used for keys + such as the SRK, which never leave the TPM. It is also used for saving state, where the entire + blob is encrypted. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StoreClear(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, /* key being stored is EK */ + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER asymSbuffer; + const unsigned char *asymBuffer; + uint32_t asymLength; + + printf(" TPM_Key_StoreClear:\n"); + TPM_Sbuffer_Init(&asymSbuffer); /* freed @1 */ + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, isEK, tpm_key); + } + /* store TPM_STORE_ASYMKEY cache as cleartext */ + if (rc == 0) { + /* if the TPM_STORE_ASYMKEY cache exists */ + if (tpm_key->tpm_store_asymkey != NULL) { + /* , serialize it */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&asymSbuffer, isEK, tpm_key->tpm_store_asymkey); + } + /* get the result */ + TPM_Sbuffer_Get(&asymSbuffer, &asymBuffer, &asymLength); + /* store the result as a sized buffer */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, asymLength); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, asymBuffer, asymLength); + } + } + /* If there is no TPM_STORE_ASYMKEY cache, mark it empty. This can occur for an internal + key that has not been created yet. */ + else { + rc = TPM_Sbuffer_Append32(sbuffer, 0); + } + } + TPM_Sbuffer_Delete(&asymSbuffer); /* @1 */ + return rc; +} + +/* TPM_KEY_StorePubkey() gets (as a stream) the TPM_PUBKEY derived from a TPM_KEY + + There is no need to actually assemble the structure, since only the serialization of its two + members are needed. + + The stream is returned as a TPM_STORE_BUFFER (that must be initialized and deleted by the + caller), and it's components (buffer and size). +*/ + +TPM_RESULT TPM_Key_StorePubkey(TPM_STORE_BUFFER *pubkeyStream, /* output */ + const unsigned char **pubkeyStreamBuffer, /* output */ + uint32_t *pubkeyStreamLength, /* output */ + TPM_KEY *tpm_key) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubkey:\n"); + /* the first part is a TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_Store(pubkeyStream, &(tpm_key->algorithmParms)); + } + /* the second part is the TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(pubkeyStream, &(tpm_key->pubKey)); + } + /* retrieve the resulting pubkey stream */ + if (rc == 0) { + TPM_Sbuffer_Get(pubkeyStream, + pubkeyStreamBuffer, + pubkeyStreamLength); + } + return rc; +} + +/* TPM_Key_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Key_Init to set members back to default values + The TPM_KEY itself is not freed + + The key is not freed because it might be a local variable rather than a malloc'ed pointer. +*/ + +void TPM_Key_Delete(TPM_KEY *tpm_key) +{ + if (tpm_key != NULL) { + printf(" TPM_Key_Delete:\n"); + TPM_KeyParms_Delete(&(tpm_key->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_key->pcrInfo)); + /* pcr caches */ + TPM_PCRInfo_Delete(tpm_key->tpm_pcr_info); + free(tpm_key->tpm_pcr_info); + TPM_PCRInfoLong_Delete(tpm_key->tpm_pcr_info_long); + free(tpm_key->tpm_pcr_info_long); + + TPM_SizedBuffer_Delete(&(tpm_key->pubKey)); + TPM_SizedBuffer_Delete(&(tpm_key->encData)); + TPM_StoreAsymkey_Delete(tpm_key->tpm_store_asymkey); + free(tpm_key->tpm_store_asymkey); + TPM_MigrateAsymkey_Delete(tpm_key->tpm_migrate_asymkey); + free(tpm_key->tpm_migrate_asymkey); + TPM_Key_Init(tpm_key); + } + return; +} + +/* TPM_Key_CheckStruct() verifies that the 'tpm_key' has either a TPM_KEY -> ver of a TPM_KEY12 tag + and fill +*/ + +TPM_RESULT TPM_Key_CheckStruct(int *ver, TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* The key can be either a TPM_KEY or TPM_KEY12 */ + if (*(unsigned char *)tpm_key == 0x01) { + *ver = 1; + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); /* check for TPM_KEY */ + if (rc == 0) { /* if found TPM_KEY */ + printf(" TPM_Key_CheckStruct: TPM_KEY version %u.%u\n", + tpm_key->ver.major, tpm_key->ver.minor); + } + } + else { /* else check for TPM_KEY12 */ + *ver = 2; + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + if (rc == 0) { + printf(" TPM_Key_CheckStruct: TPM_KEY12\n"); + } + else { /* not TPM_KEY or TPM_KEY12 */ + printf("TPM_Key_CheckStruct: Error checking structure, bytes 0:3 %02x %02x %02x %02x\n", + tpm_key->ver.major, tpm_key->ver.minor, + tpm_key->ver.revMajor, tpm_key->ver.revMinor); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckTag() checks that the TPM_KEY12 tag is correct + */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (tpm_key12->tag != TPM_TAG_KEY12) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 tag %04x should be TPM_TAG_KEY12\n", + tpm_key12->tag); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_key12->fill != 0x0000) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 fill %04x should be 0x0000\n", + tpm_key12->fill); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key'. + + if keyLength is non-zero, checks that the tpm_key specifies the correct key length. If keyLength + is 0, any tpm_key key length is accepted. + + Returns TPM_BAD_KEY_PROPERTY on error. + */ + +TPM_RESULT TPM_Key_CheckProperties(int *ver, + TPM_KEY *tpm_key, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_CheckProperties:\n"); + /* check the version */ + if (rc == 0) { + rc = TPM_Key_CheckStruct(ver, tpm_key); + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (tpm_key->authDataUsage == TPM_AUTH_NEVER) { + printf("TPM_Key_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* most of the work is done by TPM_KeyParms_CheckProperties() */ + if (rc == 0) { + printf(" TPM_Key_CheckProperties: authDataUsage %02x\n", tpm_key->authDataUsage); + rc = TPM_KeyParms_CheckProperties(&(tpm_key->algorithmParms), + tpm_key->keyUsage, + keyLength, /* in bits */ + FIPS); + } + return rc; +} + +/* TPM_Key_LoadStoreAsymKey() deserializes a stream to a TPM_STORE_ASYMKEY structure and stores it + in the TPM_KEY cache. + + Call this function when a key is loaded, either from the host (stream is decrypted encData) or + from permanent data or saved state (stream was clear text). +*/ + +TPM_RESULT TPM_Key_LoadStoreAsymKey(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, /* decrypted encData (clear text) */ + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* This function should never be called when the TPM_STORE_ASYMKEY structure has already been + loaded. This indicates an internal error. */ + printf(" TPM_Key_LoadStoreAsymKey:\n"); + if (rc == 0) { + if (tpm_key->tpm_store_asymkey != NULL) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), TPM_STORE_ASYMKEY already loaded\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* If the stream size is 0, there is an internal error. */ + if (rc == 0) { + if (*stream_size == 0) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), stream size is 0\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* allocate memory for the structure */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + rc = TPM_StoreAsymkey_Load(tpm_key->tpm_store_asymkey, isEK, + stream, stream_size, + &(tpm_key->algorithmParms), &(tpm_key->pubKey)); + TPM_PrintFour(" TPM_Key_LoadStoreAsymKey: usageAuth", + tpm_key->tpm_store_asymkey->usageAuth); + } + return rc; +} + +/* TPM_Key_GetStoreAsymkey() gets the TPM_STORE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetStoreAsymkey(TPM_STORE_ASYMKEY **tpm_store_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetStoreAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_store_asymkey = tpm_key->tpm_store_asymkey; + if (tpm_key->tpm_store_asymkey == NULL) { + printf("TPM_Key_GetStoreAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetMigrateAsymkey() gets the TPM_MIGRATE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetMigrateAsymkey(TPM_MIGRATE_ASYMKEY **tpm_migrate_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetMigrateAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_migrate_asymkey = tpm_key->tpm_migrate_asymkey; + if (tpm_key->tpm_migrate_asymkey == NULL) { + printf("TPM_Key_GetMigrateAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetUsageAuth() gets the usageAuth from the TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY + contained in a TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetUsageAuth(TPM_SECRET **usageAuth, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey; + + printf(" TPM_Key_GetUsageAuth:\n"); + /* check that the TPM_KEY_USAGE indicates a valid key */ + if (rc == 0) { + if ((tpm_key == NULL) || + (tpm_key->keyUsage == TPM_KEY_UNINITIALIZED)) { + printf("TPM_Key_GetUsageAuth: Error, key not initialized\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + + /* found a TPM_STORE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_store_asymkey->usageAuth); + } + /* get the TPM_MIGRATE_ASYMKEY object */ + else { + rc = TPM_Key_GetMigrateAsymkey(&tpm_migrate_asymkey, tpm_key); + /* found a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_migrate_asymkey->usageAuth); + } + } + } + if (rc != 0) { + printf("TPM_Key_GetUsageAuth: Error (fatal), " + "could not get TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY\n"); + rc = TPM_FAIL; /* should never occur */ + } + /* get the usageAuth element */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GetUsageAuth: Auth", **usageAuth); + } + return rc; +} + +/* TPM_Key_GetPublicKey() gets the public key from the TPM_STORE_PUBKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_key->pubKey.size; + *narr = tpm_key->pubKey.buffer; + } + return rc; +} + +/* TPM_Key_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY contained in a + TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrimeFactorP:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + } + return rc; +} + +/* TPM_Key_GetPrivateKey() gets the private key from the TPM_STORE_ASYMKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPrivateKey(uint32_t *dbytes, + unsigned char **darr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrivateKey:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *dbytes = tpm_store_asymkey->privKey.d_key.size; + *darr = tpm_store_asymkey->privKey.d_key.buffer; + } + return rc; +} + +/* TPM_Key_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_key->algorithmParms)); + } + return rc; +} + +/* TPM_Key_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_Key_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_KEY *tpm_key, + size_t start_index) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info, start_index); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info_long, start_index); + } + return rc; +} + +/* TPM_Key_GetLocalityAtRelease() the localityAtRelease for a TPM_PCR_INFO_LONG. + For a TPM_PCR_INFO is returns TPM_LOC_ALL (all localities). +*/ + +TPM_RESULT TPM_Key_GetLocalityAtRelease(TPM_LOCALITY_SELECTION *localityAtRelease, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetLocalityAtRelease:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* locality not used for TPM_PCR_INFO */ + *localityAtRelease = TPM_LOC_ALL; + } + /* TPM_KEY12 */ + else if (tpm_key->tpm_pcr_info_long == NULL) { + /* locality not used if TPM_PCR_INFO_LONG was not specified */ + *localityAtRelease = TPM_LOC_ALL; + } + else { + *localityAtRelease = tpm_key->tpm_pcr_info_long->localityAtRelease; + } + return rc; +} + +/* TPM_Key_GenerateRSA() generates a TPM_KEY using TPM_KEY_PARMS. The tag/version is set correctly. + + The TPM_STORE_ASYMKEY member cache is set. pcrInfo is set as a serialized tpm_pcr_info or + tpm_pcr_info_long. + + For exported keys, encData is not set yet. It later becomes the encryption of TPM_STORE_ASYMKEY. + + For internal 'root' keys (endorsement key, srk), encData is stored as clear text. + + It returns the TPM_KEY object. + + Call tree: + local - sets tpm_store_asymkey->privkey + TPM_Key_Set - sets keyUsage, keyFlags, authDataUsage, algorithmParms + tpm_pcr_info cache, digestAtCreation, pubKey, + TPM_Key_GeneratePubDataDigest - pubDataDigest + TPM_Key_Store + TPM_Key_StorePubData - serializes tpm_pcr_info cache +*/ + +TPM_RESULT TPM_Key_GenerateRSA(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* PCR array from state */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* input */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long) /* input */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + /* generated RSA key */ + unsigned char *n = NULL; /* public key */ + unsigned char *p = NULL; /* prime factor */ + unsigned char *q = NULL; /* prime factor */ + unsigned char *d = NULL; /* private key */ + + printf(" TPM_Key_GenerateRSA:\n"); + /* extract the TPM_RSA_KEY_PARMS from TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* get the public exponent, with conversion */ + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(&ebytes, &earr, tpm_rsa_key_parms); + } + /* allocate storage for TPM_STORE_ASYMKEY. The structure is not freed. It is cached in the + TPM_KEY->TPM_STORE_ASYMKEY member and freed when they are deleted. */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + } + /* generate the key pair */ + if (rc == 0) { + rc = TPM_RSAGenerateKeyPair(&n, /* public key (modulus) freed @3 */ + &p, /* private prime factor freed @4 */ + &q, /* private prime factor freed @5 */ + &d, /* private key (private exponent) freed @6 */ + tpm_rsa_key_parms->keyLength, /* key size in bits */ + earr, /* public exponent */ + ebytes); + } + /* construct the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GenerateRSA: Public key n", n); + TPM_PrintAll(" TPM_Key_GenerateRSA: Exponent", earr, ebytes); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime p", p); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime q", q); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private key d", d); + /* add the private primes and key to the TPM_STORE_ASYMKEY object */ + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.d_key), + tpm_rsa_key_parms->keyLength/CHAR_BIT, + d); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.p_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + p); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.q_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + q); + } + if (rc == 0) { + rc = TPM_Key_Set(tpm_key, + tpm_state, + parent_key, + tpm_pcrs, + ver, /* TPM_KEY or TPM_KEY12 */ + keyUsage, /* TPM_KEY_USAGE */ + keyFlags, /* TPM_KEY_FLAGS */ + authDataUsage, /* TPM_AUTH_DATA_USAGE */ + tpm_key_parms, /* TPM_KEY_PARMS */ + tpm_pcr_info, /* TPM_PCR_INFO */ + tpm_pcr_info_long, /* TPM_PCR_INFO_LONG */ + tpm_rsa_key_parms->keyLength/CHAR_BIT, /* TPM_STORE_PUBKEY.keyLength */ + n, /* TPM_STORE_PUBKEY.key (public key) */ + /* FIXME redundant */ + tpm_key->tpm_store_asymkey, /* cache the TPM_STORE_ASYMKEY structure */ + NULL); /* TPM_MIGRATE_ASYMKEY */ + } + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + return rc; +} + +/* TPM_Key_GeneratePubkeyDigest() serializes a TPM_PUBKEY derived from the TPM_KEY and calculates + its digest. +*/ + +TPM_RESULT TPM_Key_GeneratePubkeyDigest(TPM_DIGEST tpm_digest, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER pubkeyStream; /* from tpm_key */ + const unsigned char *pubkeyStreamBuffer; + uint32_t pubkeyStreamLength; + + printf(" TPM_Key_GeneratePubkeyDigest:\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* serialize a TPM_PUBKEY derived from the TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + tpm_key); /* input */ + } + if (rc == 0) { + rc = TPM_SHA1(tpm_digest, + pubkeyStreamLength, pubkeyStreamBuffer, + 0, NULL); + } + TPM_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rc; + +} + +/* TPM_Key_ComparePubkey() serializes and hashes the TPM_PUBKEY derived from a TPM_KEY and a + TPM_PUBKEY and compares the results +*/ + +TPM_RESULT TPM_Key_ComparePubkey(TPM_KEY *tpm_key, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + TPM_DIGEST key_digest; + TPM_DIGEST pubkey_digest; + + if (rc == 0) { + rc = TPM_Key_GeneratePubkeyDigest(key_digest, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(pubkey_digest, tpm_pubkey, + (TPM_STORE_FUNCTION_T)TPM_Pubkey_Store); + } + if (rc == 0) { + rc = TPM_Digest_Compare(key_digest, pubkey_digest); + } + return rc; +} + +/* TPM_Key_GeneratePubDataDigest() generates and stores a TPM_STORE_ASYMKEY -> pubDataDigest + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_GeneratePubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GeneratePubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_store_asymkey->pubDataDigest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_CheckPubDataDigest() generates a TPM_STORE_ASYMKEY -> pubDataDigest and compares it to + the stored value. + + Returns: Error id + */ + +TPM_RESULT TPM_Key_CheckPubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_DIGEST tpm_digest; /* calculated pubDataDigest */ + + printf(" TPM_Key_CheckPubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + if (rc == 0) { + rc = TPM_Digest_Compare(tpm_store_asymkey->pubDataDigest, tpm_digest); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_GenerateEncData() generates an TPM_KEY -> encData structure member by serializing the + cached TPM_KEY -> TPM_STORE_ASYMKEY member and encrypting the result using the parent_key public + key. +*/ + +TPM_RESULT TPM_Key_GenerateEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GenerateEncData;\n"); + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GenerateEncData(&(tpm_key->encData), + tpm_store_asymkey, + parent_key); + } + return rc; +} + + +/* TPM_Key_DecryptEncData() decrypts the TPM_KEY -> encData using the parent private key. The + result is deserialized and stored in the TPM_KEY -> TPM_STORE_ASYMKEY cache. + +*/ + +TPM_RESULT TPM_Key_DecryptEncData(TPM_KEY *tpm_key, /* result */ + TPM_KEY *parent_key) /* parent for decrypting encData */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Key_DecryptEncData\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted + data */ + tpm_key->encData.buffer, /* encrypted data */ + tpm_key->encData.size, /* encrypted data size */ + parent_key); + } + /* load the TPM_STORE_ASYMKEY cache from the 'encData' member stream */ + if (rc == 0) { + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_Key_LoadStoreAsymKey(tpm_key, FALSE, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + +/* TPM_Key_GeneratePCRDigest() generates a digest based on the current PCR state and the PCR's + specified with the key. + + The key can be either TPM_KEY or TPM_KEY12. + + This function assumes that TPM_Key_GetPCRUsage() has determined that PCR's are in use, so + a NULL PCR cache will return an error here. + + See Part 1 25.1 +*/ + +TPM_RESULT TPM_Key_CheckPCRDigest(TPM_KEY *tpm_key, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GeneratePCRDigest:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfo_CheckDigest(tpm_key->tpm_pcr_info, + tpm_state->tpm_stclear_data.PCRS); /* array of PCR's */ + } + } + else { /* TPM_KEY12 */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfoLong_CheckDigest(tpm_key->tpm_pcr_info_long, + tpm_state->tpm_stclear_data.PCRS, /* array of PCR's */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 4. Allow use of the key */ + if (rc != 0) { + printf("TPM_Key_CheckPCRDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + return rc; +} + +/* TPM_Key_CheckRestrictDelegate() checks the restrictDelegate data against the TPM_KEY properties. + It determines how the TPM responds to delegated requests to use a certified migration key. + + Called from TPM_AuthSessions_GetData() if it's a DSAP session using a key entity.. + + TPM_PERMANENT_DATA -> restrictDelegate is used as follows: + + 1. If the session type is TPM_PID_DSAP and TPM_KEY -> keyFlags -> migrateAuthority is TRUE + a. If + TPM_KEY_USAGE is TPM_KEY_SIGNING and restrictDelegate -> TPM_CMK_DELEGATE_SIGNING is TRUE, or + TPM_KEY_USAGE is TPM_KEY_STORAGE and restrictDelegate -> TPM_CMK_DELEGATE_STORAGE is TRUE, or + TPM_KEY_USAGE is TPM_KEY_BIND and restrictDelegate -> TPM_CMK_DELEGATE_BIND is TRUE, or + TPM_KEY_USAGE is TPM_KEY_LEGACY and restrictDelegate -> TPM_CMK_DELEGATE_LEGACY is TRUE, or + TPM_KEY_USAGE is TPM_KEY_MIGRATE and restrictDelegate -> TPM_CMK_DELEGATE_MIGRATE is TRUE + then the key can be used. + b. Else return TPM_INVALID_KEYUSAGE. + +*/ + +TPM_RESULT TPM_Key_CheckRestrictDelegate(TPM_KEY *tpm_key, + TPM_CMK_DELEGATE restrictDelegate) +{ + TPM_RESULT rc = 0; + + printf("TPM_Key_CheckRestrictDelegate:\n"); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_Key_CheckRestrictDelegate: Error (fatal), key NULL\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* if it's a certified migration key */ + if (rc == 0) { + if (tpm_key->keyFlags & TPM_MIGRATEAUTHORITY) { + if (!( + ((restrictDelegate & TPM_CMK_DELEGATE_SIGNING) && + (tpm_key->keyUsage == TPM_KEY_SIGNING)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_STORAGE) && + (tpm_key->keyUsage == TPM_KEY_STORAGE)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_BIND) && + (tpm_key->keyUsage == TPM_KEY_BIND)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_LEGACY) && + (tpm_key->keyUsage == TPM_KEY_LEGACY)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_MIGRATE) && + (tpm_key->keyUsage == TPM_KEY_MIGRATE)) + )) { + printf("TPM_Key_CheckRestrictDelegate: Error, " + "invalid keyUsage %04hx restrictDelegate %08x\n", + tpm_key->keyUsage, restrictDelegate); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + return rc; +} + +/* + TPM_KEY_FLAGS +*/ + +/* TPM_KeyFlags_Load() deserializes a TPM_KEY_FLAGS value and checks for a legal value. + */ + +TPM_RESULT TPM_KeyFlags_Load(TPM_KEY_FLAGS *tpm_key_flags, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + /* load keyFlags */ + if (rc == 0) { + rc = TPM_Load32(tpm_key_flags, stream, stream_size); + } + /* check TPM_KEY_FLAGS validity, look for extra bits set */ + if (rc == 0) { + if (*tpm_key_flags & ~TPM_KEY_FLAGS_MASK) { + printf("TPM_KeyFlags_Load: Error, illegal keyFlags value %08x\n", + *tpm_key_flags); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* + TPM_KEY_PARMS +*/ + +void TPM_KeyParms_Init(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Init:\n"); + tpm_key_parms->algorithmID = 0; + tpm_key_parms->encScheme = TPM_ES_NONE; + tpm_key_parms->sigScheme = TPM_SS_NONE; + TPM_SizedBuffer_Init(&(tpm_key_parms->parms)); + tpm_key_parms->tpm_rsa_key_parms = NULL; + return; +} + +#if 0 +/* TPM_KeyParms_SetRSA() is a 'Set' version specific to RSA keys */ + +TPM_RESULT TPM_KeyParms_SetRSA(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t keyLength, /* in bits */ + TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_SetRSA:\n"); + /* copy the TPM_KEY_PARMS members */ + if (rc == 0) { + tpm_key_parms->algorithmID = algorithmID; + tpm_key_parms->encScheme = encScheme; + tpm_key_parms->sigScheme = sigScheme; + /* construct the TPM_RSA_KEY_PARMS cache member object */ + rc = TPM_RSAKeyParms_New(&tpm_key_parms->tpm_rsa_key_parms); + } + if (rc == 0) { + /* copy the TPM_RSA_KEY_PARMS members */ + tpm_key_parms->tpm_rsa_key_parms->keyLength = keyLength; + tpm_key_parms->tpm_rsa_key_parms->numPrimes = 2; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms->tpm_rsa_key_parms->exponent), exponent); + } + /* serialize the TPM_RSA_KEY_PARMS object back to TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + } + return rc; +} +#endif + + +/* TPM_KeyParms_Copy() copies the source to the destination. + + If the algorithmID is TPM_ALG_RSA, the tpm_rsa_key_parms cache is allocated and copied. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Copy(TPM_KEY_PARMS *tpm_key_parms_dest, + TPM_KEY_PARMS *tpm_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Copy:\n"); + if (rc == 0) { + tpm_key_parms_dest->algorithmID = tpm_key_parms_src->algorithmID; + tpm_key_parms_dest->encScheme = tpm_key_parms_src->encScheme; + tpm_key_parms_dest->sigScheme = tpm_key_parms_src->sigScheme; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms_dest->parms), + &(tpm_key_parms_src->parms)); + } + /* if there is a destination TPM_RSA_KEY_PARMS cache */ + if ((rc == 0) && (tpm_key_parms_dest->algorithmID == TPM_ALG_RSA)) { + /* construct the TPM_RSA_KEY_PARMS cache member object */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms_dest->tpm_rsa_key_parms)); + } + /* copy the TPM_RSA_KEY_PARMS member */ + if (rc == 0) { + rc = TPM_RSAKeyParms_Copy(tpm_key_parms_dest->tpm_rsa_key_parms, + tpm_key_parms_src->tpm_rsa_key_parms); + } + } + return rc; +} + +/* TPM_KeyParms_Load deserializes a stream to a TPM_KEY_PARMS structure. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Load(TPM_KEY_PARMS *tpm_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + unsigned char *parms_stream; + uint32_t parms_stream_size; + + printf(" TPM_KeyParms_Load:\n"); + /* load algorithmID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_parms->algorithmID), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->encScheme), stream, stream_size); + } + /* load sigScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->sigScheme), stream, stream_size); + } + /* load parmSize and parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key_parms->parms), stream, stream_size); + } + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow load of uninitialized structures */ + case 0: + break; + + case TPM_ALG_RSA: + /* load the TPM_RSA_KEY_PARMS cache if the algorithmID indicates an RSA key */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms->tpm_rsa_key_parms)); + } + /* deserialize the parms stream, but don't move the pointer */ + if (rc == 0) { + parms_stream = tpm_key_parms->parms.buffer; + parms_stream_size = tpm_key_parms->parms.size; + rc = TPM_RSAKeyParms_Load(tpm_key_parms->tpm_rsa_key_parms, + &parms_stream, &parms_stream_size); + } + break; + + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Load: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + + printf(" TPM_KeyParms_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(ebytes, earr, tpm_rsa_key_parms); + } + return rc; +} + + +/* TPM_KeyParms_Store serializes a TPM_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_KeyParms_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Store:\n"); + /* store algorithmID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_parms->algorithmID); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->encScheme); + } + /* store sigScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->sigScheme); + } + /* copy cache to parms */ + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow store of uninitialized structures */ + case 0: + break; + case TPM_ALG_RSA: + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + break; + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Store: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + /* store parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key_parms->parms)); + } + return rc; +} + +/* TPM_KeyParms_Delete frees any member allocated memory */ + +void TPM_KeyParms_Delete(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Delete:\n"); + if (tpm_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_key_parms->parms)); + TPM_RSAKeyParms_Delete(tpm_key_parms->tpm_rsa_key_parms); + free(tpm_key_parms->tpm_rsa_key_parms); + TPM_KeyParms_Init(tpm_key_parms); + } + return; +} + +/* TPM_KeyParms_GetRSAKeyParms() gets the TPM_RSA_KEY_PARMS from a TPM_KEY_PARMS cache. + + Returns an error if the cache is NULL, since the cache should always be set when the + TPM_KEY_PARMS indicates an RSA key. +*/ + +TPM_RESULT TPM_KeyParms_GetRSAKeyParms(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_GetRSAKeyParms:\n"); + /* algorithmID must be RSA */ + if (rc == 0) { + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_GetRSAKeyParms: Error, incorrect algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if the TPM_RSA_KEY_PARMS structure has not been cached, deserialize it */ + if (rc == 0) { + if (tpm_key_parms->tpm_rsa_key_parms == NULL) { + printf("TPM_KeyParms_GetRSAKeyParms: Error (fatal), cache is NULL\n"); + /* This should never occur. The cache is loaded when the TPM_KEY_PARMS is loaded. */ + rc = TPM_FAIL; + } + } + /* return the cached structure */ + if (rc == 0) { + *tpm_rsa_key_parms = tpm_key_parms->tpm_rsa_key_parms; + } + return rc; +} + +/* TPM_KeyParms_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key_parms' + + if' keyLength' is non-zero, checks that the tpm_key specifies the correct key length. If + keyLength is 0, any tpm_key key length is accepted. +*/ + +TPM_RESULT TPM_KeyParms_CheckProperties(TPM_KEY_PARMS *tpm_key_parms, + TPM_KEY_USAGE tpm_key_usage, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms = NULL;/* used if algorithmID indicates RSA */ + + printf(" TPM_KeyParms_CheckProperties: keyUsage %04hx\n", tpm_key_usage); + printf(" TPM_KeyParms_CheckProperties: sigScheme %04hx\n", tpm_key_parms->sigScheme); + printf(" TPM_KeyParms_CheckProperties: encScheme %04hx\n", tpm_key_parms->encScheme); + if (rc == 0) { + /* the code currently only supports RSA */ + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_CheckProperties: Error, algorithmID not TPM_ALG_RSA\n"); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */ + /* NOTE: for now only support RSA keys */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* check key length if specified as input parameter */ + if ((rc == 0) && (keyLength != 0)) { + if (tpm_rsa_key_parms->keyLength != keyLength) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength should be %u, was %u\n", + keyLength, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_rsa_key_parms->keyLength > TPM_RSA_KEY_LENGTH_MAX) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength max %u, was %u\n", + TPM_RSA_KEY_LENGTH_MAX, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + + } + /* kgold - Support only 2 primes */ + if (rc == 0) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_KeyParms_CheckProperties: Error, numPrimes %u should be 2\n", + tpm_rsa_key_parms->numPrimes); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS */ + if (tpm_rsa_key_parms->keyLength < 1024) { + printf("TPM_KeyParms_CheckProperties: Error, Invalid FIPS key length %u\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_NOTFIPS; + } + /* c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS */ + else if (tpm_key_usage == TPM_KEY_LEGACY) { + printf("TPM_KeyParms_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* From Part 2 5.7.1 Mandatory Key Usage Schemes and TPM_CreateWrapKey, TPM_LoadKey */ + if (rc == 0) { + switch (tpm_key_usage) { + case TPM_KEY_UNINITIALIZED: + printf("TPM_KeyParms_CheckProperties: Error, keyUsage TPM_KEY_UNINITIALIZED\n"); + rc = TPM_BAD_KEY_PROPERTY; + break; + case TPM_KEY_SIGNING: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } +#ifdef TPM_V12 + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { +#else /* TPM 1.1 */ + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + +#endif + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing sigScheme %04hx is not DER, SHA1, INFO\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_STORAGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_IDENTITY: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity sigScheme %04hx is not %04x\n", + tpm_key_parms->sigScheme, TPM_SS_RSASSAPKCS1v15_SHA1); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_AUTHCHANGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_rsa_key_parms->keyLength < 512) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange keyLength %d is less than 512\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_BIND: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_LEGACY: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy sigScheme %04hx is not %04x or %04x\n", + tpm_key_parms->sigScheme, + TPM_SS_RSASSAPKCS1v15_SHA1, TPM_SS_RSASSAPKCS1v15_DER); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_MIGRATE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + default: + printf("TPM_KeyParms_CheckProperties: Error, Unknown keyUsage %04hx\n", tpm_key_usage); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParams_CheckDefaultExponent(TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + uint32_t i; + + if ((rc == 0) && (exponent->size != 0)) { /* 0 is the default */ + printf(" TPM_KeyParams_CheckDefaultExponent: exponent size %u\n", exponent->size); + if (rc == 0) { + if (exponent->size < 3) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent size is %u\n", + exponent->size); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + for (i = 3 ; i < exponent->size ; i++) { + if (exponent->buffer[i] != 0) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent[%u] is %02x\n", + i, exponent->buffer[i]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + if (rc == 0) { + if ((exponent->buffer[0] != tpm_default_rsa_exponent[0]) || + (exponent->buffer[1] != tpm_default_rsa_exponent[1]) || + (exponent->buffer[2] != tpm_default_rsa_exponent[2])) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent is %02x %02x %02x\n", + exponent->buffer[2], exponent->buffer[1], exponent->buffer[0]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + return rc; +} + +/* + TPM_STORE_ASYMKEY +*/ + +void TPM_StoreAsymkey_Init(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Init:\n"); + tpm_store_asymkey->payload = TPM_PT_ASYM; + TPM_Secret_Init(tpm_store_asymkey->usageAuth); + TPM_Secret_Init(tpm_store_asymkey->migrationAuth); + TPM_Digest_Init(tpm_store_asymkey->pubDataDigest); + TPM_StorePrivkey_Init(&(tpm_store_asymkey->privKey)); + return; +} + +/* TPM_StoreAsymkey_Load() deserializes the TPM_STORE_ASYMKEY structure. + + The serialized structure contains the private factor p. Normally, 'tpm_key_parms' and + tpm_store_pubkey are not NULL and the private key d is derived from p and the public key n and + exponent e. + + In some cases, a TPM_STORE_ASYMKEY is being manipulated without the rest of the TPM_KEY + structure. When 'tpm_key' is NULL, p is left intact, and the resulting structure cannot be used + as a private key. +*/ + +TPM_RESULT TPM_StoreAsymkey_Load(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *pubKey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Load:\n"); + /* load payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Load8(&(tpm_store_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if ((rc == 0) && !isEK) { + if ( + /* normal key */ + (tpm_store_asymkey->payload != TPM_PT_ASYM) && + /* TPM_CMK_CreateKey payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + /* TPM_CMK_ConvertMigration payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_EXTERNAL) + ) { + printf("TPM_StoreAsymkey_Load: Error, invalid payload %02x\n", + tpm_store_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->usageAuth, stream, stream_size); + } + /* load migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->migrationAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_store_asymkey->pubDataDigest, stream, stream_size); + } + /* load privKey - actually prime factor p */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load((&(tpm_store_asymkey->privKey.p_key)), + stream, stream_size); + } + /* convert prime factor p to the private key */ + if ((rc == 0) && (tpm_key_parms != NULL) && (pubKey != NULL)) { + rc = TPM_StorePrivkey_Convert(tpm_store_asymkey, + tpm_key_parms, pubKey); + } + return rc; +} + +#if 0 +static TPM_RESULT TPM_StoreAsymkey_LoadTest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + int irc; + + /* actual */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr; + unsigned char *darr; + + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + /* computed */ + unsigned char *q1arr = NULL; + unsigned char *d1arr = NULL; + + uint32_t q1bytes; + uint32_t d1bytes; + + printf(" TPM_StoreAsymkey_LoadTest:\n"); + /* actual data */ + if (rc == 0) { + narr = tpm_key->pubKey.key; + darr = tpm_key->tpm_store_asymkey->privKey.d_key; + parr = tpm_key->tpm_store_asymkey->privKey.p_key; + qarr = tpm_key->tpm_store_asymkey->privKey.q_key; + + nbytes = tpm_key->pubKey.keyLength; + dbytes = tpm_key->tpm_store_asymkey->privKey.d_keyLength; + pbytes = tpm_key->tpm_store_asymkey->privKey.p_keyLength; + qbytes = tpm_key->tpm_store_asymkey->privKey.q_keyLength; + + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetPrimeFactorP(&pbytes, &parr, tpm_key); + } + /* computed data */ + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&q1bytes, &q1arr, /* freed @1 */ + &d1bytes, &d1arr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + /* compare q */ + if (rc == 0) { + if (qbytes != q1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qbytes %u q1bytes %u\n", + qbytes, q1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(qarr, q1arr, qbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qarr mismatch\n"); + rc = TPM_FAIL; + } + } + /* compare d */ + if (rc == 0) { + if (dbytes != d1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), dbytes %u d1bytes %u\n", + dbytes, d1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(darr, d1arr, dbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), darr mismatch\n"); + rc = TPM_FAIL; + } + } + free(q1arr); /* @1 */ + free(d1arr); /* @2 */ + return rc; +} +#endif + +TPM_RESULT TPM_StoreAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + const TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Store:\n"); + /* store payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_store_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->usageAuth); + } + /* store migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->migrationAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_store_asymkey->pubDataDigest); + } + /* store privKey */ + if (rc == 0) { + rc = TPM_StorePrivkey_Store(sbuffer, &(tpm_store_asymkey->privKey)); + } + return rc; +} + +void TPM_StoreAsymkey_Delete(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Delete:\n"); + if (tpm_store_asymkey != NULL) { + TPM_Secret_Delete(tpm_store_asymkey->usageAuth); + TPM_Secret_Delete(tpm_store_asymkey->migrationAuth); + TPM_StorePrivkey_Delete(&(tpm_store_asymkey->privKey)); + TPM_StoreAsymkey_Init(tpm_store_asymkey); + } + return; +} + +TPM_RESULT TPM_StoreAsymkey_GenerateEncData(TPM_SIZED_BUFFER *encData, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORE_ASYMKEY serialization */ + + printf(" TPM_StoreAsymkey_GenerateEncData;\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(encData, &sbuffer, parent_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_StoreAsymkey_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY +*/ + +TPM_RESULT TPM_StoreAsymkey_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_GetPrimeFactorP:\n"); + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + TPM_PrintFour(" TPM_StoreAsymkey_GetPrimeFactorP:", *parr); + } + return rc; +} + +/* TPM_StoreAsymkey_GetO1Size() calculates the destination o1 size for a TPM_STORE_ASYMKEY + + Used for creating a migration blob, TPM_STORE_ASYMKEY -> TPM_MIGRATE_ASYMKEY. + */ + +void TPM_StoreAsymkey_GetO1Size(uint32_t *o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + *o1_size = tpm_store_asymkey->privKey.p_key.size + /* private key */ + sizeof(uint32_t) - /* private key length */ + TPM_DIGEST_SIZE + /* - k1 -> k2 TPM_MIGRATE_ASYMKEY -> partPrivKey */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1; /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_GetO1Size: key size %u o1 size %u\n", + tpm_store_asymkey->privKey.p_key.size, *o1_size); +} + +/* TPM_StoreAsymkey_CheckO1Size() verifies the destination o1_size against the source k1k2 array + length + + This is a currently just a sanity check on the TPM_StoreAsymkey_GetO1Size() function. +*/ + +TPM_RESULT TPM_StoreAsymkey_CheckO1Size(uint32_t o1_size, + uint32_t k1k2_length) +{ + TPM_RESULT rc = 0; + + /* sanity check the TPM_MIGRATE_ASYMKEY size against the requested o1 size */ + /* K1 K2 are the length and value of the private key, 4 + 128 bytes for a 2048-bit key */ + if (o1_size < + (k1k2_length - TPM_DIGEST_SIZE + /* k1 k2, the first 20 bytes are used as the OAEP seed */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1)) { /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_CheckO1Size: Error (fatal) k1k2_length %d too large for o1 %u\n", + k1k2_length, o1_size); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_StoreAsymkey_StoreO1() creates an OAEP encoded TPM_MIGRATE_ASYMKEY from a + TPM_STORE_ASYMKEY. + + It does the common steps of constructing the TPM_MIGRATE_ASYMKEY, serializing it, and OAEP + padding. +*/ + +TPM_RESULT TPM_StoreAsymkey_StoreO1(BYTE *o1, + uint32_t o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SECRET usageAuth) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER k1k2_sbuffer; /* serialization of TPM_STORE_ASYMKEY -> privKey -> key */ + const unsigned char *k1k2; /* serialization results */ + uint32_t k1k2_length; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER tpm_migrate_asymkey_sbuffer; /* serialized tpm_migrate_asymkey */ + const unsigned char *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + + printf(" TPM_StoreAsymkey_StoreO1:\n"); + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @1 */ + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @2 */ + TPM_Sbuffer_Init(&tpm_migrate_asymkey_sbuffer); /* freed @3 */ + + /* NOTE Comments from TPM_CreateMigrationBlob rev 81 */ + /* a. Build two byte arrays, K1 and K2: */ + /* i. K1 = TPM_STORE_ASYMKEY.privKey[0..19] (TPM_STORE_ASYMKEY.privKey.keyLength + 16 bytes of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K1) = 20 */ + /* ii. K2 = TPM_STORE_ASYMKEY.privKey[20..131] (position 16-127 of + TPM_STORE_ASYMKEY. privKey.key), sizeof(K2) = 112 */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(&k1k2_sbuffer, &(tpm_store_asymkey->privKey.p_key)); + } + if (rc == 0) { + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2, &k1k2_length); + /* sanity check the TPM_STORE_ASYMKEY -> privKey -> key size against the requested o1 + size */ + rc = TPM_StoreAsymkey_CheckO1Size(o1_size, k1k2_length); + } + /* b. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* i. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_MIGRATE */ + /* ii. TPM_MIGRATE_ASYMKEY.usageAuth = TPM_STORE_ASYMKEY.usageAuth */ + /* iii. TPM_MIGRATE_ASYMKEY.pubDataDigest = TPM_STORE_ASYMKEY. pubDataDigest */ + /* iv. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* v. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + if (rc == 0) { + tpm_migrate_asymkey.payload = payload_type; + TPM_Secret_Copy(tpm_migrate_asymkey.usageAuth, usageAuth); + TPM_Digest_Copy(tpm_migrate_asymkey.pubDataDigest, tpm_store_asymkey->pubDataDigest); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k1 -", k1k2); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k2 -", k1k2 + TPM_DIGEST_SIZE); + rc = TPM_SizedBuffer_Set(&(tpm_migrate_asymkey.partPrivKey), + k1k2_length - TPM_DIGEST_SIZE, /* k2 length 112 for 2048 bit key */ + k1k2 + TPM_DIGEST_SIZE); /* k2 */ + } + /* c. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* i. m = M1 the TPM_MIGRATE_ASYMKEY structure */ + /* ii. pHash = d1->migrationAuth */ + /* iii. seed = s1 = K1 */ + if (rc == 0) { + /* serialize TPM_MIGRATE_ASYMKEY m */ + rc = TPM_MigrateAsymkey_Store(&tpm_migrate_asymkey_sbuffer, &tpm_migrate_asymkey); + } + if (rc == 0) { + /* get the serialization result */ + TPM_Sbuffer_Get(&tpm_migrate_asymkey_sbuffer, + &tpm_migrate_asymkey_buffer, &tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: pHash -", pHash); + rc = TPM_RSA_padding_add_PKCS1_OAEP(o1, /* output */ + o1_size, + tpm_migrate_asymkey_buffer, /* message */ + tpm_migrate_asymkey_length, + pHash, + k1k2); /* k1, seed */ + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: o1 -", o1); + } + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @1 */ + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @2 */ + TPM_Sbuffer_Delete(&tpm_migrate_asymkey_sbuffer); /* @3 */ + return rc; +} + +/* TPM_StoreAsymkey_LoadO1() extracts TPM_STORE_ASYMKEY from the OAEP encoded TPM_MIGRATE_ASYMKEY. + + It does the common steps OAEP depadding, deserializing the TPM_MIGRATE_ASYMKEY, and + reconstructing the TPM_STORE_ASYMKEY. + + It sets these, which may or may not be correct at a higher level + + TPM_STORE_ASYMKEY -> payload = TPM_MIGRATE_ASYMKEY -> payload + TPM_STORE_ASYMKEY -> usageAuth = TPM_MIGRATE_ASYMKEY -> usageAuth + TPM_STORE_ASYMKEY -> migrationAuth = pHash + TPM_STORE_ASYMKEY -> pubDataDigest = TPM_MIGRATE_ASYMKEY -> pubDataDigest + TPM_STORE_ASYMKEY -> privKey = seed + TPM_MIGRATE_ASYMKEY -> partPrivKey +*/ + +TPM_RESULT TPM_StoreAsymkey_LoadO1(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* output */ + BYTE *o1, /* input */ + uint32_t o1_size) /* input */ +{ + TPM_RESULT rc = 0; + BYTE *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + TPM_DIGEST seed; + TPM_DIGEST pHash; + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER k1k2_sbuffer; + const unsigned char *k1k2_buffer; + uint32_t k1k2_length; + + printf(" TPM_StoreAsymkey_LoadO1:\n"); + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @1 */ + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @2 */ + tpm_migrate_asymkey_buffer = NULL; /* freed @3 */ + /* allocate memory for TPM_MIGRATE_ASYMKEY after removing OAEP pad from o1 */ + if (rc == 0) { + rc = TPM_Malloc(&tpm_migrate_asymkey_buffer, o1_size); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: o1 -", o1); + /* 5. Create m1, seed and pHash by OAEP decoding o1 */ + printf(" TPM_StoreAsymkey_LoadO1: Depadding\n"); + rc = TPM_RSA_padding_check_PKCS1_OAEP(tpm_migrate_asymkey_buffer, /* out: to */ + &tpm_migrate_asymkey_length, /* out: to length */ + o1_size, /* to size */ + o1, o1_size, /* from, from length */ + pHash, + seed); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_buffer -", + tpm_migrate_asymkey_buffer); + printf(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_length %u\n", + tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - pHash", pHash); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - seed", seed); + } + /* deserialize the buffer back to a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + stream = tpm_migrate_asymkey_buffer; + stream_size = tpm_migrate_asymkey_length; + rc = TPM_MigrateAsymkey_Load(&tpm_migrate_asymkey, &stream, &stream_size); + printf(" TPM_StoreAsymkey_LoadO1: partPrivKey length %u\n", + tpm_migrate_asymkey.partPrivKey.size); + TPM_PrintFourLimit(" TPM_StoreAsymkey_LoadO1: partPrivKey -", + tpm_migrate_asymkey.partPrivKey.buffer, + tpm_migrate_asymkey.partPrivKey.size); + } + /* create k1k2 by combining seed (k1) and TPM_MIGRATE_ASYMKEY.partPrivKey (k2) field */ + if (rc == 0) { + rc = TPM_Digest_Store(&k1k2_sbuffer, seed); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(&k1k2_sbuffer, + tpm_migrate_asymkey.partPrivKey.buffer, + tpm_migrate_asymkey.partPrivKey.size); + } + /* assemble the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + tpm_store_asymkey->payload = tpm_migrate_asymkey.payload; + TPM_Digest_Copy(tpm_store_asymkey->usageAuth, tpm_migrate_asymkey.usageAuth); + TPM_Digest_Copy(tpm_store_asymkey->migrationAuth, pHash); + TPM_Digest_Copy(tpm_store_asymkey->pubDataDigest, tpm_migrate_asymkey.pubDataDigest); + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2_buffer, &k1k2_length); + printf(" TPM_StoreAsymkey_LoadO1: k1k2 length %u\n", k1k2_length); + TPM_PrintFourLimit(" TPM_StoreAsymkey_LoadO1: k1k2", k1k2_buffer, k1k2_length); + rc = TPM_SizedBuffer_Load(&(tpm_store_asymkey->privKey.p_key), + (unsigned char **)&k1k2_buffer, &k1k2_length); + } + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @1 */ + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @2 */ + free(tpm_migrate_asymkey_buffer); /* @3 */ + return rc; +} + + +/* + TPM_MIGRATE_ASYMKEY +*/ + +/* TPM_MigrateAsymkey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_MigrateAsymkey_Init(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Init:\n"); + tpm_migrate_asymkey->payload = TPM_PT_MIGRATE; + TPM_Secret_Init(tpm_migrate_asymkey->usageAuth); + TPM_Digest_Init(tpm_migrate_asymkey->pubDataDigest); + TPM_SizedBuffer_Init(&(tpm_migrate_asymkey->partPrivKey)); + return; +} + +/* TPM_MigrateAsymkey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_MigrateAsymkey_Init() + After use, call TPM_MigrateAsymkey_Delete() to free memory +*/ + +TPM_RESULT TPM_MigrateAsymkey_Load(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_migrate_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if (rc == 0) { + if ((tpm_migrate_asymkey->payload != TPM_PT_MIGRATE) && + (tpm_migrate_asymkey->payload != TPM_PT_MAINT) && + (tpm_migrate_asymkey->payload != TPM_PT_CMK_MIGRATE)) { + printf("TPM_MigrateAsymkey_Load: Error illegal payload %02x\n", + tpm_migrate_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_migrate_asymkey->usageAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_migrate_asymkey->pubDataDigest, stream, stream_size); + } + /* load partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_migrate_asymkey->partPrivKey), stream, stream_size); + } + return rc; +} + +/* TPM_MigrateAsymkey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_MigrateAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_migrate_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_migrate_asymkey->usageAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_migrate_asymkey->pubDataDigest); + } + /* store partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_migrate_asymkey->partPrivKey)); + } + return rc; +} + +/* TPM_MigrateAsymkey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_MigrateAsymkey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_MigrateAsymkey_Delete(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Delete:\n"); + if (tpm_migrate_asymkey != NULL) { + TPM_Secret_Delete(tpm_migrate_asymkey->usageAuth); + TPM_SizedBuffer_Zero(&(tpm_migrate_asymkey->partPrivKey)); + TPM_SizedBuffer_Delete(&(tpm_migrate_asymkey->partPrivKey)); + TPM_MigrateAsymkey_Init(tpm_migrate_asymkey); + } + return; +} + +/* + TPM_STORE_PRIVKEY +*/ + +void TPM_StorePrivkey_Init(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Init:\n"); + TPM_SizedBuffer_Init(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->q_key)); + return; +} + +/* TPM_StorePrivkey_Convert() sets the prime factor q and private key d based on the prime factor p + and the public key and exponent. +*/ + +TPM_RESULT TPM_StorePrivkey_Convert(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* I/O result */ + TPM_KEY_PARMS *tpm_key_parms, /* to get exponent */ + TPM_SIZED_BUFFER *pubKey) /* to get public key */ +{ + TPM_RESULT rc = 0; + /* computed data */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr = NULL; + unsigned char *darr = NULL; + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + + printf(" TPM_StorePrivkey_Convert:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: p", tpm_store_asymkey->privKey.p_key.buffer); + nbytes = pubKey->size; + narr = pubKey->buffer; + rc = TPM_KeyParms_GetExponent(&ebytes, &earr, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GetPrimeFactorP(&pbytes, &parr, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&qbytes, &qarr, /* freed @1 */ + &dbytes, &darr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: q", qarr); + TPM_PrintFour(" TPM_StorePrivkey_Convert: d", darr); + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.q_key)), qbytes, qarr); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.d_key)), dbytes, darr); + } + free(qarr); /* @1 */ + free(darr); /* @2 */ + return rc; +} + +/* TPM_StorePrivkey_Store serializes a TPM_STORE_PRIVKEY structure, appending results to 'sbuffer' + + Only the prime factor p is stored. The other prime factor q and the private key d are + recalculated after a load. + */ + +TPM_RESULT TPM_StorePrivkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StorePrivkey_Store:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Store: p", tpm_store_privkey->p_key.buffer); + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_store_privkey->p_key)); + } + return rc; +} + +void TPM_StorePrivkey_Delete(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Delete:\n"); + if (tpm_store_privkey != NULL) { + TPM_SizedBuffer_Zero(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->q_key)); + + TPM_SizedBuffer_Delete(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->q_key)); + TPM_StorePrivkey_Init(tpm_store_privkey); + } + return; +} + +/* + TPM_PUBKEY +*/ + +void TPM_Pubkey_Init(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Init:\n"); + TPM_KeyParms_Init(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_pubkey->pubKey)); + return; +} + +TPM_RESULT TPM_Pubkey_Load(TPM_PUBKEY *tpm_pubkey, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Load:\n"); + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_pubkey->algorithmParms), stream, stream_size); + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_pubkey->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Pubkey_Store serializes a TPM_PUBKEY structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_Pubkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Store:\n"); + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_pubkey->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_pubkey->pubKey)); + } + return rc; +} + +void TPM_Pubkey_Delete(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Delete:\n"); + if (tpm_pubkey != NULL) { + TPM_KeyParms_Delete(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Delete(&(tpm_pubkey->pubKey)); + TPM_Pubkey_Init(tpm_pubkey); + } + return; +} + +TPM_RESULT TPM_Pubkey_Set(TPM_PUBKEY *tpm_pubkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Set:\n"); + if (rc == 0) { + /* add TPM_KEY_PARMS algorithmParms */ + rc = TPM_KeyParms_Copy(&(tpm_pubkey->algorithmParms), + &(tpm_key->algorithmParms)); + } + if (rc == 0) { + /* add TPM_SIZED_BUFFER pubKey */ + rc = TPM_SizedBuffer_Copy(&(tpm_pubkey->pubKey), + &(tpm_key->pubKey)); + } + return rc; +} + +TPM_RESULT TPM_Pubkey_Copy(TPM_PUBKEY *dest_tpm_pubkey, + TPM_PUBKEY *src_tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Copy:\n"); + /* copy TPM_KEY_PARMS algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(dest_tpm_pubkey->algorithmParms), + &(src_tpm_pubkey->algorithmParms)); + } + /* copy TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(dest_tpm_pubkey->pubKey), + &(src_tpm_pubkey->pubKey)); + } + return rc; + +} + +/* TPM_Pubkey_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a + TPM_PUBKEY +*/ + +TPM_RESULT TPM_Pubkey_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_pubkey->algorithmParms)); + } + return rc; +} + +/* TPM_Pubkey_GetPublicKey() gets the public key from the TPM_PUBKEY + */ + +TPM_RESULT TPM_Pubkey_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_pubkey->pubKey.size; + *narr = tpm_pubkey->pubKey.buffer; + } + return rc; +} + +/* + TPM_RSA_KEY_PARMS +*/ + + +/* Allocates and loads a TPM_RSA_KEY_PARMS structure + + Must be delete'd and freed by the caller. +*/ + +void TPM_RSAKeyParms_Init(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Init:\n"); + tpm_rsa_key_parms->keyLength = 0; + tpm_rsa_key_parms->numPrimes = 0; + TPM_SizedBuffer_Init(&(tpm_rsa_key_parms->exponent)); + return; +} + +/* TPM_RSAKeyParms_Load() sets members from stream, and shifts the stream past the bytes consumed. + + Must call TPM_RSAKeyParms_Delete() to free +*/ + +TPM_RESULT TPM_RSAKeyParms_Load(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Load:\n"); + /* load keyLength */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->keyLength), stream, stream_size); + } + /* load numPrimes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->numPrimes), stream, stream_size); + } + /* load exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_rsa_key_parms->exponent), stream, stream_size); + } + return rc; +} + +/* TPM_RSAKeyParms_Store serializes a TPM_RSA_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_RSAKeyParms_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Store:\n"); + /* store keyLength */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->keyLength); + } + /* store numPrimes */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->numPrimes); + } + /* store exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_rsa_key_parms->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_Delete frees any member allocated memory + + If 'tpm_rsa_key_parms' is NULL, this is a no-op. + */ + +void TPM_RSAKeyParms_Delete(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Delete:\n"); + if (tpm_rsa_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_rsa_key_parms->exponent)); + TPM_RSAKeyParms_Init(tpm_rsa_key_parms); + } + return; +} + +/* TPM_RSAKeyParms_Copy() does a copy of the source to the destination. + + The destination must be initialized first. +*/ + +TPM_RESULT TPM_RSAKeyParms_Copy(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_dest, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Copy:\n"); + if (rc == 0) { + tpm_rsa_key_parms_dest->keyLength = tpm_rsa_key_parms_src->keyLength; + tpm_rsa_key_parms_dest->numPrimes = tpm_rsa_key_parms_src->numPrimes; + rc = TPM_SizedBuffer_Copy(&(tpm_rsa_key_parms_dest->exponent), + &(tpm_rsa_key_parms_src->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_New() allocates memory for a TPM_RSA_KEY_PARMS and initializes the structure */ + +TPM_RESULT TPM_RSAKeyParms_New(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_New:\n"); + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_rsa_key_parms, sizeof(TPM_RSA_KEY_PARMS)); + } + if (rc == 0) { + TPM_RSAKeyParms_Init(*tpm_rsa_key_parms); + } + return rc; +} + +/* TPM_RSAKeyParms_GetExponent() gets the exponent array and size from tpm_rsa_key_parms. + + If the structure exponent.size is zero, the default RSA exponent is returned. +*/ + +TPM_RESULT TPM_RSAKeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_GetExponent:\n"); + if (tpm_rsa_key_parms->exponent.size != 0) { + *ebytes = tpm_rsa_key_parms->exponent.size; + *earr = tpm_rsa_key_parms->exponent.buffer; + } + else { + *ebytes = 3; + *earr = tpm_default_rsa_exponent; + } + return rc; +} + +/* + A Key Handle Entry +*/ + +/* TPM_KeyHandleEntry_Init() removes an entry from the list. It DOES NOT delete the + TPM_KEY object. */ + +void TPM_KeyHandleEntry_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + tpm_key_handle_entry->handle = 0; + tpm_key_handle_entry->key = NULL; + tpm_key_handle_entry->parentPCRStatus = TRUE; + tpm_key_handle_entry->keyControl = 0; + return; +} + +/* TPM_KeyHandleEntry_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_KeyHandleEntry_Init() + After use, call TPM_KeyHandleEntry_Delete() to free memory +*/ + +TPM_RESULT TPM_KeyHandleEntry_Load(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Load:\n"); + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->handle), stream, stream_size); + } + /* malloc space for the key member */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key_handle_entry->key), sizeof(TPM_KEY)); + } + /* load key */ + if (rc == 0) { + TPM_Key_Init(tpm_key_handle_entry->key); + rc = TPM_Key_LoadClear(tpm_key_handle_entry->key, + FALSE, /* not EK */ + stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_key_handle_entry->parentPCRStatus), stream, stream_size); + } + /* load keyControl */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->keyControl), stream, stream_size); + } + return rc; +} + +/* TPM_KeyHandleEntry_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_KeyHandleEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Store:\n"); + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->handle); + } + /* store key with private data appended in clear text */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, + FALSE, /* not EK */ + tpm_key_handle_entry->key); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_key_handle_entry->parentPCRStatus), sizeof(TPM_BOOL)); + } + /* store keyControl */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->keyControl); + } + return rc; +} + +/* TPM_KeyHandleEntry_Delete() deletes an entry from the list, deletes the TPM_KEY object, and + free's the TPM_KEY. +*/ + +void TPM_KeyHandleEntry_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + if (tpm_key_handle_entry != NULL) { + if (tpm_key_handle_entry->handle != 0) { + printf(" TPM_KeyHandleEntry_Delete: Deleting %08x\n", tpm_key_handle_entry->handle); + TPM_Key_Delete(tpm_key_handle_entry->key); + free(tpm_key_handle_entry->key); + } + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return; +} + +/* TPM_KeyHandleEntry_FlushSpecific() flushes a key handle according to the rules of + TPM_FlushSpecific() +*/ + +TPM_RESULT TPM_KeyHandleEntry_FlushSpecific(tpm_state_t *tpm_state, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + TPM_AUTHHANDLE authHandle = 0; /* dummy parameter */ + TPM_BOOL continueAuthSession; /* dummy parameter */ + + printf(" TPM_KeyHandleEntry_FlushSpecific:\n"); + if (rc == 0) { + /* Internal error, should never happen */ + if (tpm_key_handle_entry->key == NULL) { + printf("TPM_KeyHandleEntry_FlushSpecific: Error (fatal), key is NULL\n"); + rc = TPM_FAIL; + } + } + /* terminate OSAP and DSAP sessions associated with the key */ + if (rc == 0) { + /* The dummy parameters are not used. The session, if any, associated with this function + is handled elsewhere. */ + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_KEYHANDLE, /* TPM_ENTITY_TYPE */ + &(tpm_key_handle_entry->key-> + tpm_store_asymkey->pubDataDigest)); /* entityDigest */ + printf(" TPM_KeyHandleEntry_FlushSpecific: Flushing key handle %08x\n", + tpm_key_handle_entry->handle); + /* free the TPM_KEY resources, free the key itself, and remove entry from the key handle + entries list */ + TPM_KeyHandleEntry_Delete(tpm_key_handle_entry); + } + return rc; +} + +/* + Key Handle Entries +*/ + +/* TPM_KeyHandleEntries_Init() initializes the fixed TPM_KEY_HANDLE_ENTRY array. All entries are + emptied. The keys are not deleted. +*/ + +void TPM_KeyHandleEntries_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Init:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Init(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Delete() deletes and freed all TPM_KEY's stored in entries, and the entry + +*/ + +void TPM_KeyHandleEntries_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Delete:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Load() loads the key handle entries from a stream created by + TPM_KeyHandleEntries_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t keyCount = 0; /* keys to be saved */ + size_t i; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY_HANDLE_ENTRIES_V1, stream, stream_size); + } + /* get the count of keys in the stream */ + if (rc == 0) { + rc = TPM_Load32(&keyCount, stream, stream_size); + printf(" TPM_KeyHandleEntries_Load: %u keys to be loaded\n", keyCount); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_Load: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_KEY_HANDLES); + rc = TPM_FAIL; + } + } + /* for each key handle entry */ + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* deserialize the key handle entry and its key member */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Load: Loading key handle %08x\n", + tpm_key_handle_entry.handle); + /* Add the entry to the list. Keep the handle. If the suggested value could not be + accepted, this is a "should never happen" fatal error. It means that the save key + handle was saved twice. */ + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_Store() stores the key handle entries to a stream that can be restored + through TPM_KeyHandleEntries_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + size_t start; /* iterator though key handle entries */ + size_t current; /* iterator though key handle entries */ + uint32_t keyCount; /* keys to be saved */ + TPM_BOOL save; /* should key be saved */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY_HANDLE_ENTRIES_V1); + } + /* first count up the keys */ + if (rc == 0) { + start = 0; + keyCount = 0; + printf(" TPM_KeyHandleEntries_Store: Counting keys to be stored\n"); + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + keyCount++; + } + start = current + 1; + } + /* store the number of entries to save */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: %u keys to be stored\n", keyCount); + rc = TPM_Sbuffer_Append32(sbuffer, keyCount); + } + /* for each key handle entry */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: Storing keys\n"); + start = 0; + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + /* store the key handle entry and its associated key */ + rc = TPM_KeyHandleEntry_Store(sbuffer, tpm_key_handle_entry); + } + start = current + 1; + } + return rc; +} + + + +/* TPM_KeyHandleEntries_StoreHandles() stores only the two members which are part of the + specification. + + - the number of loaded keys + - a list of key handles + + A TPM_KEY_HANDLE_LIST structure that enumerates all key handles loaded on the TPM. The list only + contains the number of handles that an external manager can operate with and does not include the + EK or SRK. This is command is available for backwards compatibility. It is the same as + TPM_CAP_HANDLE with a resource type of keys. +*/ + +TPM_RESULT TPM_KeyHandleEntries_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i, loadedCount; + + printf(" TPM_KeyHandleEntries_StoreHandles:\n"); + if (rc == 0) { + loadedCount = 0; + /* count the number of loaded handles */ + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { + loadedCount++; + } + } + /* store 'loaded' handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loadedCount); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entries[i].handle); /* store it */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_DeleteHandle() removes a handle from the list. + + The TPM_KEY object must be _Delete'd and possibly free'd separately, because it might not be in + the table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_DeleteHandle(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_DeleteHandle: %08x\n", tpm_key_handle); + /* search for the handle */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_DeleteHandle: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* delete the entry */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return rc; +} + +/* TPM_KeyHandleEntries_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_KeyHandleEntries_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + printf(" TPM_KeyHandleEntries_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_KEY_HANDLES ; (*index)++) { + if (tpm_key_handle_entries[*index].key == NULL) { /* if the index is empty */ + printf(" TPM_KeyHandleEntries_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_KeyHandleEntries_GetSpace() returns the number of unused key handle entries. + +*/ + +void TPM_KeyHandleEntries_GetSpace(uint32_t *space, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint32_t i; + + printf(" TPM_KeyHandleEntries_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + (*space)++; + } + } + return; +} + +/* TPM_KeyHandleEntries_IsEvictSpace() returns 'isSpace' TRUE if there are at least 'minSpace' + entries that do not have the ownerEvict bit set, FALSE if not. +*/ + +void TPM_KeyHandleEntries_IsEvictSpace(TPM_BOOL *isSpace, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t minSpace) +{ + uint32_t evictSpace; + uint32_t i; + + for (i = 0, evictSpace = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + evictSpace++; + } + else { /* is index is used */ + if (!(tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + evictSpace++; /* space that can be evicted */ + } + } + } + printf(" TPM_KeyHandleEntries_IsEvictSpace: evictable space, minimum %u free %u\n", + minSpace, evictSpace); + if (evictSpace >= minSpace) { + *isSpace = TRUE; + } + else { + *isSpace = FALSE; + } + return; +} + +/* TPM_KeyHandleEntries_AddKeyEntry() adds a TPM_KEY object to the list. + + If *tpm_key_handle == 0, a value is assigned. If *tpm_key_handle != 0, + that value is used if it it not currently in use. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddKeyEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* in */ + TPM_KEY *tpm_key, + TPM_BOOL parentPCRStatus, + TPM_KEY_CONTROL keyControl) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_AddKeyEntry:\n"); + tpm_key_handle_entry.key = tpm_key; + tpm_key_handle_entry.parentPCRStatus = parentPCRStatus; + tpm_key_handle_entry.keyControl = keyControl; + rc = TPM_KeyHandleEntries_AddEntry(tpm_key_handle, + FALSE, /* don't have to keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + return rc; +} + +/* TPM_KeyHandleEntries_AddEntry() adds (copies) the TPM_KEY_HANDLE_ENTRY object to the list. + + If *tpm_key_handle == 0: + a value is assigned. + + If *tpm_key_handle != 0: + + If keepHandle is TRUE, the handle must be used. An error is returned if the handle is + already in use. + + If keepHandle is FALSE, if the handle is already in use, a new value is assigned. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) /* input */ + +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_KeyHandleEntries_AddEntry: handle %08x, keepHandle %u\n", + *tpm_key_handle, keepHandle); + /* check for valid TPM_KEY */ + if (rc == 0) { + if (tpm_key_handle_entry->key == NULL) { /* should never occur */ + printf("TPM_KeyHandleEntries_AddEntry: Error (fatal), NULL TPM_KEY\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entries); + if (!isSpace) { + printf("TPM_KeyHandleEntries_AddEntry: Error, key handle entries full\n"); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_key_handle, /* I/O */ + tpm_key_handle_entries, /* handle array */ + keepHandle, + TRUE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_KeyHandleEntries_GetEntry); + } + if (rc == 0) { + tpm_key_handle_entries[index].handle = *tpm_key_handle; + tpm_key_handle_entries[index].key = tpm_key_handle_entry->key; + tpm_key_handle_entries[index].keyControl = tpm_key_handle_entry->keyControl; + tpm_key_handle_entries[index].parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + printf(" TPM_KeyHandleEntries_AddEntry: Index %u key handle %08x key pointer %p\n", + index, tpm_key_handle_entries[index].handle, tpm_key_handle_entries[index].key); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetEntry() searches all entries for the entry matching the handle, and + returns that entry */ + +TPM_RESULT TPM_KeyHandleEntries_GetEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_KeyHandleEntries_GetEntry: Get entry for handle %08x\n", tpm_key_handle); + for (i = 0, found = FALSE ; (i < TPM_KEY_HANDLES) && !found ; i++) { + /* first test for matching handle. Then check for non-NULL to insure that entry is valid */ + if ((tpm_key_handle_entries[i].handle == tpm_key_handle) && + tpm_key_handle_entries[i].key != NULL) { /* found */ + found = TRUE; + *tpm_key_handle_entry = &(tpm_key_handle_entries[i]); + } + } + if (!found) { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x not found\n", tpm_key_handle); + rc = TPM_INVALID_KEYHANDLE; + } + else { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x found\n", tpm_key_handle); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetNextEntry() gets the next valid TPM_KEY_HANDLE_ENTRY at or after the + 'start' index. + + The current position is returned in 'current'. For iteration, the next 'start' should be + 'current' + 1. + + Returns + + 0 on success. + Returns TPM_RETRY when no more valid entries are found. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetNextEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + size_t *current, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + size_t start) +{ + TPM_RESULT rc = TPM_RETRY; + + printf(" TPM_KeyHandleEntries_GetNextEntry: Start %lu\n", (unsigned long)start); + for (*current = start ; *current < TPM_KEY_HANDLES ; (*current)++) { + if (tpm_key_handle_entries[*current].key != NULL) { + *tpm_key_handle_entry = &(tpm_key_handle_entries[*current]); + rc = 0; /* found an entry */ + break; + } + } + return rc; +} + +/* TPM_KeyHandleEntries_GetKey() gets the TPM_KEY associated with the handle. + + If the key has PCR usage (size is non-zero and one or more mask bits are set), PCR's have been + specified. It computes a PCR digest based on the TPM PCR's and verifies it against the key + digestAtRelease. + + Exceptions: readOnly is TRUE when the caller is indicating that only the public key is being read + (e.g. TPM_GetPubKey). In this case, if keyFlags TPM_PCRIGNOREDONREAD is also TRUE, the PCR + digest and locality must not be checked. + + If ignorePCRs is TRUE, the PCR digest is also ignored. A typical case is during OSAP and DSAP + session setup. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetKey(TPM_KEY **tpm_key, + TPM_BOOL *parentPCRStatus, + tpm_state_t *tpm_state, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL readOnly, + TPM_BOOL ignorePCRs, + TPM_BOOL allowEK) +{ + TPM_RESULT rc = 0; + TPM_BOOL found = FALSE; /* found a special handle key */ + TPM_BOOL validatePcrs = TRUE; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_GetKey: For handle %08x\n", tpm_key_handle); + /* If it's one of the special handles, return the TPM_KEY */ + if (rc == 0) { + switch (tpm_key_handle) { + case TPM_KH_SRK: /* The handle points to the SRK */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + *tpm_key = &(tpm_state->tpm_permanent_data.srk); + *parentPCRStatus = FALSE; /* storage root key (SRK) has no parent */ + found = TRUE; + } + else { + printf(" TPM_KeyHandleEntries_GetKey: Error, SRK handle with no owner\n"); + rc = TPM_KEYNOTFOUND; + } + break; + case TPM_KH_EK: /* The handle points to the PUBEK, only usable with + TPM_OwnerReadInternalPub */ + if (rc == 0) { + if (!allowEK) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle not allowed\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == + TPM_KEY_UNINITIALIZED) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle but no EK\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + *tpm_key = &(tpm_state->tpm_permanent_data.endorsementKey); + *parentPCRStatus = FALSE; /* endorsement key (EK) has no parent */ + found = TRUE; + } + break; + case TPM_KH_OWNER: /* handle points to the TPM Owner */ + case TPM_KH_REVOKE: /* handle points to the RevokeTrust value */ + case TPM_KH_TRANSPORT: /* handle points to the EstablishTransport static authorization */ + case TPM_KH_OPERATOR: /* handle points to the Operator auth */ + case TPM_KH_ADMIN: /* handle points to the delegation administration auth */ + printf("TPM_KeyHandleEntries_GetKey: Error, Unsupported key handle %08x\n", + tpm_key_handle); + rc = TPM_INVALID_RESOURCE; + break; + default: + /* continue searching */ + break; + } + } + /* If not one of the special key handles, search for the handle in the list */ + if ((rc == 0) && !found) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_GetKey: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* Part 1 25.1 Validate Key for use + 2. Set LK to the loaded key that is being used */ + /* NOTE: For special handle keys, this was already done. Just do here for keys in table */ + if ((rc == 0) && !found) { + *tpm_key = tpm_key_handle_entry->key; + *parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + } + /* 3. If LK -> pcrInfoSize is not 0 - if the key specifies PCR's */ + /* NOTE Done by TPM_Key_CheckPCRDigest() */ + /* a. If LK -> pcrInfo -> releasePCRSelection identifies the use of one or more PCR */ + if (rc == 0) { +#ifdef TPM_V12 + validatePcrs = !ignorePCRs && + !(readOnly && ((*tpm_key)->keyFlags & TPM_PCRIGNOREDONREAD)); +#else + validatePcrs = !ignorePCRs && !readOnly; +#endif + } + if ((rc == 0) && validatePcrs) { + if (rc == 0) { + rc = TPM_Key_CheckPCRDigest(*tpm_key, tpm_state); + } + } + return rc; +} + +/* TPM_KeyHandleEntries_SetParentPCRStatus() updates the parentPCRStatus member of the + TPM_KEY_HANDLE_ENTRY */ + +TPM_RESULT TPM_KeyHandleEntries_SetParentPCRStatus(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL parentPCRStatus) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_SetParentPCRStatus: Handle %08x\n", tpm_key_handle); + /* get the entry for the handle from the table */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_SetParentPCRStatus: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + if (rc == 0) { + tpm_key_handle_entry->parentPCRStatus = parentPCRStatus; + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictLoad() loads all owner evict keys from the stream into the key + handle entries table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictLoad(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t keyCount; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; /* each entry as read from the stream */ + TPM_TAG ownerEvictVersion; + + printf(" TPM_KeyHandleEntries_OwnerEvictLoad:\n"); + /* get the owner evict version number */ + if (rc == 0) { + rc = TPM_Load16(&ownerEvictVersion, stream, stream_size); + } + if (rc == 0) { + if (ownerEvictVersion != TPM_TAG_NVSTATE_OE_V1) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: " + "Error (fatal) unsupported version tag %04x\n", + ownerEvictVersion); + rc = TPM_FAIL; + } + } + /* get the count of owner evict keys in the stream */ + if (rc == 0) { + rc = TPM_Load16(&keyCount, stream, stream_size); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Count %hu\n", keyCount); + } + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* Must init each time through. This just resets the structure members. It does not free + the key that is in the structure after the first time through. That key has been added + (copied) to the key handle entries array. */ + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Loading key %hu\n", i); + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + if (rc == 0) { + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + /* add the entry to the list */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictStore() stores all owner evict keys from the key handle entries + table to the stream. + + It is used to serialize to NVRAM. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictStore(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t count; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictStore:\n"); + /* append the owner evict version number to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_OE_V1); + } + /* count the number of owner evict keys */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictGetCount(&count, tpm_key_handle_entries); + } + /* append the count to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, count); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + /* store it */ + rc = TPM_KeyHandleEntry_Store(sbuffer, &(tpm_key_handle_entries[i])); + } + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictGetCount returns the number of owner evict key entries + */ + +TPM_RESULT +TPM_KeyHandleEntries_OwnerEvictGetCount(uint16_t *count, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount:\n"); + /* count the number of loaded owner evict handles */ + if (rc == 0) { + for (i = 0 , *count = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + (*count)++; /* count it */ + } + } + } + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount: Count %hu\n", *count); + } + /* sanity check */ + if (rc == 0) { + if (*count > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictGetCount: Error (fatal), " + "count greater that max %u\n", TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictDelete() flushes owner evict keys. It does NOT write to NV. + +*/ + +void TPM_KeyHandleEntries_OwnerEvictDelete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + } + } + return; +} + +/* + Processing Functions +*/ + +/* 14.4 TPM_ReadPubek rev 99 + + Return the endorsement key public portion. This value should have controls placed upon access as + it is a privacy sensitive value + + The readPubek flag is set to FALSE by TPM_TakeOwnership and set to TRUE by TPM_OwnerClear, thus + mirroring if a TPM Owner is present. +*/ + +TPM_RESULT TPM_Process_ReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; + + /* processing */ + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; + TPM_DIGEST checksum; + + printf("TPM_Process_ReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_ReadPubek: antiReplay", antiReplay); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If TPM_PERMANENT_FLAGS -> readPubek is FALSE return TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: readPubek %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + if (!tpm_state->tpm_permanent_flags.readPubek) { + printf("TPM_Process_ReadPubek: Error, readPubek is FALSE\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. If no EK is present the TPM MUST return TPM_NO_ENDORSEMENT */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == TPM_KEY_UNINITIALIZED) { + printf("TPM_Process_ReadPubek: Error, no EK is present\n"); + returnCode = TPM_NO_ENDORSEMENT; + } + } + /* 3. Create checksum by performing SHA-1 on the concatenation of (pubEndorsementKey || + antiReplay). */ + if (returnCode == TPM_SUCCESS) { + /* serialize the TPM_PUBKEY components of the EK */ + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: pubEndorsementKey length %u\n", + pubEndorsementKeyStreamLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, +#if 0 /* The old Atmel chip and the LTC test code assume this, but it is incorrect */ + tpm_state->tpm_permanent_data.endorsementKey.pubKey.keyLength, + tpm_state->tpm_permanent_data.endorsementKey.pubKey.key, +#else /* this meets the TPM 1.2 standard */ + pubEndorsementKeyStreamLength, pubEndorsementKeyStreamBuffer, +#endif + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadPubek: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* 4. Export the PUBEK and checksum. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append pubEndorsementKey */ + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 14.2 TPM_CreateRevocableEK rev 98 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. The TPM vendor may have a separate mechanism to create the EK and "squirt" the + value into the TPM. +*/ + +TPM_RESULT TPM_Process_CreateRevocableEK(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + TPM_BOOL generateReset = FALSE; /* If TRUE use TPM RNG to generate EKreset. If FALSE + use the passed value inputEKreset */ + TPM_NONCE inputEKreset; /* The authorization value to be used with TPM_RevokeTrust + if generateReset==FALSE, else the parameter is present + but unused */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_KEY *endorsementKey; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back NV */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateRevocableEK: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* get generateReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&generateReset, &command, ¶mSize); + } + /* get inputEKreset parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateRevocableEK: generateReset %02x\n", generateReset); + /* an email clarification says that this parameter is still present (but ignored) if + generateReset is TRUE */ + returnCode = TPM_Nonce_Load(inputEKreset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateRevocableEK: inputEKreset", inputEKreset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateRevocableEK: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + /* 2. Perform the actions of TPM_CreateEndorsementKeyPair, if any errors return with error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + if (returnCode == TPM_SUCCESS) { + /* 3. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to TRUE */ + TPM_SetCapability_Flag(&writeAllNV1, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + TRUE); /* value */ + /* a. If generateReset is TRUE then */ + if (generateReset) { + /* i. Set TPM_PERMANENT_DATA -> EKreset to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_permanent_data.EKReset); + } + /* b. Else */ + else { + /* i. Set TPM_PERMANENT_DATA -> EKreset to inputEkreset */ + TPM_Nonce_Copy(tpm_state->tpm_permanent_data.EKReset, inputEKreset); + } + } + /* save the permanent data and flags structure sto NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateRevocableEK: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 4. Return PUBEK, checksum and Ekreset */ + /* append pubEndorsementKey. */ + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + } + /* append outputEKreset */ + /* 5. The outputEKreset authorization is sent in the clear. There is no uniqueness on the + TPM available to actually perform encryption or use an encrypted channel. The assumption + is that this operation is occurring in a controlled environment and sending the value in + the clear is acceptable. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, tpm_state->tpm_permanent_data.EKReset); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* 14.1 TPM_CreateEndorsementKeyPair rev 104 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. +*/ + +TPM_RESULT TPM_Process_CreateEndorsementKeyPair(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ + TPM_KEY *endorsementKey = FALSE; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateEndorsementKeyPair: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateEndorsementKeyPair: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + /* 10. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to FALSE */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + FALSE); /* value */ + } + /* save the permanent data and flags structures to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateEndorsementKeyPair: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* append pubEndorsementKey. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* TPM_CreateEndorsementKeyPair_Common rev 104 + + Actions common to TPM_CreateEndorsementKeyPair and TPM_CreateRevocableEK + + 'endorsementKey' points to TPM_PERMANENT_DATA -> endorsementKey +*/ + +TPM_RESULT TPM_CreateEndorsementKeyPair_Common(TPM_KEY *endorsementKey, /* output */ + TPM_PUBKEY *pubEndorsementKey, /* output */ + TPM_DIGEST checksum, /* output */ + TPM_BOOL *writePermanentData, /* output */ + tpm_state_t *tpm_state, /* input */ + TPM_KEY_PARMS *keyInfo, /* input */ + TPM_NONCE antiReplay) /* input */ +{ + TPM_RESULT returnCode = TPM_SUCCESS; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* from keyInfo */ + TPM_STORE_BUFFER pubEndorsementKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubEndorsementKeyBuffer; + uint32_t pubEndorsementKeyLength; + + printf("TPM_CreateEndorsementKeyPair_Common:\n"); + TPM_Sbuffer_Init(&pubEndorsementKeySerial); /* freed @1 */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + if (endorsementKey->keyUsage != TPM_KEY_UNINITIALIZED) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, key already initialized\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. Validate the keyInfo parameters for the key description */ + if (returnCode == TPM_SUCCESS) { + /* + RSA + */ + /* a. If the algorithm type is RSA the key length MUST be a minimum of + 2048. For interoperability the key length SHOULD be 2048 */ + if (keyInfo->algorithmID == TPM_ALG_RSA) { + if (returnCode == TPM_SUCCESS) { + /* get the keyInfo TPM_RSA_KEY_PARMS structure */ + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->keyLength != TPM_KEY_RSA_NUMBITS) { /* in bits */ + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad keyLength should be %u, was %u\n", + TPM_KEY_RSA_NUMBITS, tpm_rsa_key_parms->keyLength); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* kgold - Support only 2 primes */ + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad numPrimes should be 2, was %u\n", + tpm_rsa_key_parms->numPrimes); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* + not RSA + */ + /* b. If the algorithm type is other than RSA the strength provided by + the key MUST be comparable to RSA 2048 */ + else { + if (returnCode == TPM_SUCCESS) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "algorithmID %08x not supported\n", + keyInfo->algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* c. The other parameters of keyInfo (encScheme, sigScheme, etc.) are ignored. + */ + /* 3. Create a key pair called the "endorsement key pair" using a TPM-protected capability. The + type and size of key are that indicated by keyInfo. Set encScheme to + TPM_ES_RSAESOAEP_SHA1_MGF1. + + Save the endorsement key in permanent structure. Save the endorsement private key 'd' in the + TPM_KEY structure as encData */ + /* Certain HW TPMs do not ignore the encScheme parameter, and expect it to be + TPM_ES_RSAESOAEP_SHA1_MGF1. Test the value here to detect an application program that will + fail with that TPM. */ + + if (returnCode == TPM_SUCCESS) { + if (keyInfo->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + returnCode = TPM_BAD_KEY_PROPERTY; + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "encScheme %08x must be TPM_ES_RSAESOAEP_SHA1_MGF1\n", + keyInfo->encScheme); + } + } + if (returnCode == TPM_SUCCESS) { + keyInfo->sigScheme = TPM_ES_NONE; + returnCode = TPM_Key_GenerateRSA(endorsementKey, + tpm_state, + NULL, /* parent key, indicate root key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + 1, /* TPM_KEY */ + TPM_KEY_STORAGE, /* keyUsage */ + 0, /* keyFlags */ + TPM_AUTH_ALWAYS, /* authDataUsage */ + keyInfo, + NULL, /* no PCR's */ + NULL); /* no PCR's */ + *writePermanentData = TRUE; + } + /* Assemble the TPM_PUBKEY pubEndorsementKey for the response */ + if (returnCode == TPM_SUCCESS) { + /* add TPM_KEY_PARMS algorithmParms */ + returnCode = TPM_KeyParms_Copy(&(pubEndorsementKey->algorithmParms), + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + /* add TPM_SIZED_BUFFER pubKey */ + returnCode = TPM_SizedBuffer_Set(&(pubEndorsementKey->pubKey), + endorsementKey->pubKey.size, + endorsementKey->pubKey.buffer); + } + /* 4. Create checksum by performing SHA-1 on the concatenation of (PUBEK + || antiReplay) */ + if (returnCode == TPM_SUCCESS) { + /* serialize the pubEndorsementKey */ + returnCode = TPM_Pubkey_Store(&pubEndorsementKeySerial, + pubEndorsementKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubEndorsementKeySerial, + &pubEndorsementKeyBuffer, &pubEndorsementKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubEndorsementKeyLength, pubEndorsementKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* 5. Store the PRIVEK */ + /* NOTE Created in TPM_PERMANENT_DATA, call should save to NVRAM */ + /* 6. Create TPM_PERMANENT_DATA -> tpmDAASeed from the TPM RNG */ + /* 7. Create TPM_PERMANENT_DATA -> daaProof from the TPM RNG */ + /* 8. Create TPM_PERMANENT_DATA -> daaBlobKey from the TPM RNG */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + /* 9. Set TPM_PERMANENT_FLAGS -> CEKPUsed to TRUE */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_permanent_flags.CEKPUsed = TRUE; + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeySerial); /* @1 */ + return returnCode; +} + +/* 14.3 TPM_RevokeTrust rev 98 + + This command clears the EK and sets the TPM back to a pure default state. The generation of the + AuthData value occurs during the generation of the EK. It is the responsibility of the EK + generator to properly protect and disseminate the RevokeTrust AuthData. +*/ + +TPM_RESULT TPM_Process_RevokeTrust(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE EKReset; /* The value that will be matched to EK Reset */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + TPM_BOOL writeAllNV3 = FALSE; /* flags to write back flags */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_RevokeTrust: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get EKReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(EKReset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_RevokeTrust: EKReset", EKReset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_RevokeTrust: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM MUST validate that TPM_PERMANENT_FLAGS -> enableRevokeEK is TRUE, return + TPM_PERMANENTEK on error */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.enableRevokeEK) { + printf("TPM_Process_RevokeTrust: Error, enableRevokeEK is FALSE\n"); + returnCode = TPM_PERMANENTEK; + } + } + /* 2. The TPM MUST validate that the EKReset matches TPM_PERMANENT_DATA -> EKReset, return + TPM_AUTHFAIL on error. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Compare(tpm_state->tpm_permanent_data.EKReset, EKReset); + if (returnCode != 0) { + printf("TPM_Process_RevokeTrust: Error, EKReset mismatch\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. Ensure that physical presence is being asserted */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_RevokeTrust: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 4. Perform the actions of TPM_OwnerClear (excepting the command authentication) */ + /* a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This changes the + TPM_OwnerClear handling of the same NV areas */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + TRUE); /* delete all NVRAM */ + writeAllNV1 = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to FALSE */ + TPM_SetCapability_Flag(&writeAllNV2, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.nvLocked), /* flag */ + FALSE); /* value */ + /* 5. Invalidate TPM_PERMANENT_DATA -> tpmDAASeed */ + /* 6. Invalidate TPM_PERMANENT_DATA -> daaProof */ + /* 7. Invalidate TPM_PERMANENT_DATA -> daaBlobKey */ + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + if (returnCode == TPM_SUCCESS) { + /* 8. Invalidate the EK and any internal state associated with the EK */ + printf("TPM_Process_RevokeTrust: Deleting endorsement key\n"); + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.endorsementKey)); + TPM_SetCapability_Flag(&writeAllNV3, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.CEKPUsed), /* flag */ + FALSE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV1, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_RevokeTrust: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 27.7 TPM_DisablePubekRead rev 94 + + The TPM Owner may wish to prevent any entity from reading the PUBEK. This command sets the + non-volatile flag so that the TPM_ReadPubek command always returns TPM_DISABLED_CMD. + + This commands has in essence been deprecated as TPM_TakeOwnership now sets the value to false. + The commands remains at this time for backward compatibility. +*/ + +TPM_RESULT TPM_Process_DisablePubekRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisablePubekRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisablePubekRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that the TPM Owner authorizes the command and all of the input, on error return + TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 1. This capability sets the TPM_PERMANENT_FLAGS -> readPubek flag to FALSE. */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.readPubek), /* flag */ + FALSE); /* value */ + printf("TPM_Process_DisablePubekRead: readPubek now %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + /* save the permanent flags structure to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisablePubekRead: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 27.6 TPM_OwnerReadPubek rev 94 + + Return the endorsement key public portion. This is authorized by the TPM Owner. +*/ + +TPM_RESULT TPM_Process_OwnerReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; /* The public endorsement key */ + + printf("TPM_Process_OwnerReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner authorization to execute this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* serialize the TPM_PUBKEY components of the EK */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadPubek: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Export the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 27.1.1 TPM_EvictKey rev 87 + + The key commands are deprecated as the new way to handle keys is to use the standard context + commands. So TPM_EvictKey is now handled by TPM_FlushSpecific, TPM_TerminateHandle by + TPM_FlushSpecific. + + The TPM will invalidate the key stored in the specified handle and return the space to the + available internal pool for subsequent query by TPM_GetCapability and usage by TPM_LoadKey. If + the specified key handle does not correspond to a valid key, an error will be returned. +*/ + +TPM_RESULT TPM_Process_EvictKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE evictHandle; /* The handle of the key to be evicted. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* table entry for the evictHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_EvictKey: Ordinal Entry\n"); + /* + get inputs + */ + /* get evictHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&evictHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_EvictKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* New 1.2 functionality + The command must check the status of the ownerEvict flag for the key and if the flag is TRUE + return TPM_KEY_CONTROL_OWNER + */ + /* evict the key stored in the specified handle */ + /* get the TPM_KEY_HANDLE_ENTRY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Evicting handle %08x\n", evictHandle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + evictHandle); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Error, key handle %08x not found\n", + evictHandle); + } + } + /* If tpm_key_handle_entry -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_EvictKey: Error, keyHandle specifies owner evict\n"); + returnCode = TPM_KEY_OWNER_CONTROL; + } + } + /* delete the entry, delete the key structure, and free the key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_EvictKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 14.5 TPM_OwnerReadInternalPub rev 87 + + A TPM Owner authorized command that returns the public portion of the EK or SRK. + + The keyHandle parameter is included in the incoming session authorization to prevent + alteration of the value, causing a different key to be read. Unlike most key handles, which + can be mapped by higher layer software, this key handle has only two fixed values. + +*/ + +TPM_RESULT TPM_Process_OwnerReadInternalPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters */ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle for either PUBEK or SRK */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *readKey = NULL; /* key to be read back */ + const unsigned char *stream; + uint32_t stream_size; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerReadInternalPub: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + /* NOTE: This is a special case, where the keyHandle is part of the HMAC calculation to + avoid a man-in-the-middle privacy attack that replaces the SRK handle with the EK + handle. */ + inParamStart = command; + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OwnerReadInternalPub: keyHandle %08x\n", keyHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadInternalPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the parameters and TPM Owner AuthData for this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 2. If keyHandle is TPM_KH_EK */ + if (keyHandle == TPM_KH_EK) { + /* a. Set publicPortion to PUBEK */ + printf("TPM_Process_OwnerReadInternalPub: Reading EK\n"); + readKey = &(tpm_state->tpm_permanent_data.endorsementKey); + } + /* 3. Else If keyHandle is TPM_KH_SRK */ + else if (keyHandle == TPM_KH_SRK) { + /* a. Set publicPortion to the TPM_PUBKEY of the SRK */ + printf("TPM_Process_OwnerReadInternalPub: Reading SRK\n"); + readKey = &(tpm_state->tpm_permanent_data.srk); + } + /* 4. Else return TPM_BAD_PARAMETER */ + else { + printf("TPM_Process_OwnerReadInternalPub: Error, invalid keyHandle %08x\n", + keyHandle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadInternalPub: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 5. Export the public key of the referenced key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(response, &stream, &stream_size, readKey); + } + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + + |