/********************************************************************************/
/*										*/
/*			    TSS Primary API for TPM 2.0				*/
/*			     Written by Ken Goldman				*/
/*		       IBM Thomas J. Watson Research Center			*/
/*										*/
/* (c) Copyright IBM Corporation 2018 - 2022					*/
/*										*/
/* All rights reserved.								*/
/* 										*/
/* Redistribution and use in source and binary forms, with or without		*/
/* modification, are permitted provided that the following conditions are	*/
/* met:										*/
/* 										*/
/* Redistributions of source code must retain the above copyright notice,	*/
/* this list of conditions and the following disclaimer.			*/
/* 										*/
/* Redistributions in binary form must reproduce the above copyright		*/
/* notice, this list of conditions and the following disclaimer in the		*/
/* documentation and/or other materials provided with the distribution.		*/
/* 										*/
/* Neither the names of the IBM Corporation nor the names of its		*/
/* contributors may be used to endorse or promote products derived from		*/
/* this software without specific prior written permission.			*/
/* 										*/
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS		*/
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT		*/
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR	*/
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT		*/
/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,	*/
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT		*/
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,	*/
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY	*/
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT		*/
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE	*/
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.		*/
/********************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>

#ifdef TPM_POSIX
#include <netinet/in.h>
#endif
#ifdef TPM_WINDOWS
#include <winsock2.h>
#endif

#include "tssauth.h"
#include "tssauth20.h"
#include <ibmtss/tss.h>
#include "tssproperties.h"
#include <ibmtss/tsstransmit.h>
#include <ibmtss/tssutils.h>
#include <ibmtss/tssresponsecode.h>
#include <ibmtss/tssmarshal.h>
#include <ibmtss/Unmarshal_fp.h>
#include "tssccattributes.h"
#ifndef TPM_TSS_NOCRYPTO
#include <ibmtss/tsscrypto.h>
#include <ibmtss/tsscryptoh.h>
#endif
#include <ibmtss/tssprintcmd.h>
#include "tss20.h"

/* Files:

   h01xxxxxx.bin - NV index name
   h02xxxxxx.bin - hmac session context
   h03xxxxxx.bin - policy session context
   h80xxxxxx.bin - transient object name

   cxxxx...xxxx.bin - context blob name
*/

/* NOTE Synchronize with

   TSS_HmacSession_InitContext
   TSS_HmacSession_Unmarshal
   TSS_HmacSession_Marshal
*/

struct TSS_HMAC_CONTEXT {
    TPMI_SH_AUTH_SESSION	sessionHandle;		/* the session handle */
    TPMI_ALG_HASH		authHashAlg;		/* hash algorithm to use for the session */
#ifndef TPM_TSS_NOCRYPTO
    uint32_t           		sizeInBytes;		/* hash algorithm mapped to size */
#endif	/* TPM_TSS_NOCRYPTO */
    TPMT_SYM_DEF 		symmetric;		/* the algorithm and key size for parameter
							   encryption */
    TPMI_DH_ENTITY 		bind;			/* bind handle */
    TPM2B_NAME			bindName;		/* Name corresponding to the the bind
							   handle */
    TPM2B_AUTH			bindAuthValue;		/* password corresponding to the bind
							   handle */
#ifndef TPM_TSS_NOCRYPTO
    TPM2B_NONCE 		nonceTPM;		/* from TPM in response */
    TPM2B_NONCE			nonceCaller;		/* from caller in command */
    TPM2B_DIGEST		sessionKey;		/* from KDFa at session creation */
#endif	/* TPM_TSS_NOCRYPTO */
    TPM_SE			sessionType;		/* HMAC (0), policy (1), or trial policy */
    uint8_t			isPasswordNeeded;	/* flag set by policy password */
    uint8_t			isAuthValueNeeded;	/* flag set by policy authvalue */
    /* Items below this line are for the lifetime of one command.  They are not saved and loaded. */
    TPM2B_KEY			hmacKey;		/* HMAC key calculated for each command */
#ifndef TPM_TSS_NOCRYPTO
    TPM2B_KEY			sessionValue;		/* KDFa secret for parameter encryption */
#endif	/* TPM_TSS_NOCRYPTO */
} TSS_HMAC_CONTEXT;

/* functions for command pre- and post- processing */

#ifdef TPM_TSS_NODEPRECATEDALGS
typedef TPM_RC (*TSS_CheckParametersFunction_t)(COMMAND_PARAMETERS *in);
#endif /* TPM_TSS_NODEPRECATEDALGS */
typedef TPM_RC (*TSS_PreProcessFunction_t)(TSS_CONTEXT *tssContext,
					   COMMAND_PARAMETERS *in,
					   EXTRA_PARAMETERS *extra);
typedef TPM_RC (*TSS_ChangeAuthFunction_t)(TSS_CONTEXT *tssContext,
					   struct TSS_HMAC_CONTEXT *session,
					   size_t handleNumber,
					   COMMAND_PARAMETERS *in);
typedef TPM_RC (*TSS_PostProcessFunction_t)(TSS_CONTEXT *tssContext,
					    COMMAND_PARAMETERS *in,
					    RESPONSE_PARAMETERS *out,
					    EXTRA_PARAMETERS *extra);

static TPM_RC TSS_PR_StartAuthSession(TSS_CONTEXT *tssContext,
				      StartAuthSession_In *in,
				      StartAuthSession_Extra *extra);
static TPM_RC TSS_PR_NV_DefineSpace(TSS_CONTEXT *tssContext,
				    NV_DefineSpace_In *in,
				    void *extra);

static TPM_RC TSS_CA_HierarchyChangeAuth(TSS_CONTEXT *tssContext,
					 struct TSS_HMAC_CONTEXT *session,
					 size_t handleNumber,
					 HierarchyChangeAuth_In *in);
static TPM_RC TSS_CA_NV_UndefineSpaceSpecial(TSS_CONTEXT *tssContext,
					     struct TSS_HMAC_CONTEXT *session,
					     size_t handleNumber,
					     NV_UndefineSpaceSpecial_In *in);
static TPM_RC TSS_CA_NV_ChangeAuth(TSS_CONTEXT *tssContext,
				   struct TSS_HMAC_CONTEXT *session,
				   size_t handleNumber,
				   NV_ChangeAuth_In *in);


static TPM_RC TSS_PO_StartAuthSession(TSS_CONTEXT *tssContext,
				      StartAuthSession_In *in,
				      StartAuthSession_Out *out,
				      StartAuthSession_Extra *extra);
static TPM_RC TSS_PO_ContextSave(TSS_CONTEXT *tssContext,
				 ContextSave_In *in,
				 ContextSave_Out *out,
				 void *extra);
static TPM_RC TSS_PO_ContextLoad(TSS_CONTEXT *tssContext,
				 ContextLoad_In *in,
				 ContextLoad_Out *out,
				 void *extra);
static TPM_RC TSS_PO_FlushContext(TSS_CONTEXT *tssContext,
				  FlushContext_In *in,
				  void *out,
				  void *extra);
static TPM_RC TSS_PO_EvictControl(TSS_CONTEXT *tssContext,
				  EvictControl_In *in,
				  void *out,
				  void *extra);
static TPM_RC TSS_PO_Load(TSS_CONTEXT *tssContext,
			  Load_In *in,
			  Load_Out *out,
			  void *extra);
static TPM_RC TSS_PO_LoadExternal(TSS_CONTEXT *tssContext,
				  LoadExternal_In *in,
				  LoadExternal_Out *out,
				  void *extra);
static TPM_RC TSS_PO_ReadPublic(TSS_CONTEXT *tssContext,
				ReadPublic_In *in,
				ReadPublic_Out *out,
				void *extra);
static TPM_RC TSS_PO_CreateLoaded(TSS_CONTEXT *tssContext,
				  CreateLoaded_In *in,
				  CreateLoaded_Out *out,
				  void *extra);
static TPM_RC TSS_PO_HMAC_Start(TSS_CONTEXT *tssContext,
				HMAC_Start_In *in,
				HMAC_Start_Out *out,
				void *extra);
static TPM_RC TSS_PO_HashSequenceStart(TSS_CONTEXT *tssContext,
				       HashSequenceStart_In *in,
				       HashSequenceStart_Out *out,
				       void *extra);
static TPM_RC TSS_PO_SequenceComplete(TSS_CONTEXT *tssContext,
				      SequenceComplete_In *in,
				      SequenceComplete_Out *out,
				      void *extra);
static TPM_RC TSS_PO_EventSequenceComplete(TSS_CONTEXT *tssContext,
					   EventSequenceComplete_In *in,
					   EventSequenceComplete_Out *out,
					   void *extra);
static TPM_RC TSS_PO_PolicyAuthValue(TSS_CONTEXT *tssContext,
				     PolicyAuthValue_In *in,
				     void *out,
				     void *extra);
static TPM_RC TSS_PO_PolicyPassword(TSS_CONTEXT *tssContext,
				    PolicyPassword_In *in,
				    void *out,
				    void *extra);
static TPM_RC TSS_PO_CreatePrimary(TSS_CONTEXT *tssContext,
				   CreatePrimary_In *in,
				   CreatePrimary_Out *out,
				   void *extra);
static TPM_RC TSS_PO_NV_DefineSpace(TSS_CONTEXT *tssContext,
				    NV_DefineSpace_In *in,
				    void *out,
				    void *extra);
static TPM_RC TSS_PO_NV_ReadPublic(TSS_CONTEXT *tssContext,
				   NV_ReadPublic_In *in,
				   NV_ReadPublic_Out *out,
				   void *extra);
static TPM_RC TSS_PO_NV_UndefineSpace(TSS_CONTEXT *tssContext,
				      NV_UndefineSpace_In *in,
				      void *out,
				      void *extra);
static TPM_RC TSS_PO_NV_UndefineSpaceSpecial(TSS_CONTEXT *tssContext,
					     NV_UndefineSpaceSpecial_In *in,
					     void *out,
					     void *extra);
static TPM_RC TSS_PO_NV_Write(TSS_CONTEXT *tssContext,
			      NV_Write_In *in,
			      void *out,
			      void *extra);
static TPM_RC TSS_PO_NV_WriteLock(TSS_CONTEXT *tssContext,
				  NV_WriteLock_In *in,
				  void *out,
				  void *extra);
static TPM_RC TSS_PO_NV_ReadLock(TSS_CONTEXT *tssContext,
				 NV_ReadLock_In *in,
				 void *out,
				 void *extra);

#ifdef TPM_TSS_NODEPRECATEDALGS

/*
  Functions to check for usage of deprecated algorithms.
*/

static TPM_RC TSS_CheckSha1_PublicArea(TPMT_PUBLIC *publicArea)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (publicArea->nameAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    if (rc == 0) {
	if (((publicArea->type == TPM_ALG_RSA) || (publicArea->type == TPM_ALG_ECC)) &&
	    (publicArea->parameters.asymDetail.scheme.scheme != TPM_ALG_NULL) &&
	    (publicArea->parameters.asymDetail.scheme.details.anySig.hashAlg == TPM_ALG_SHA1)) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CheckSha1_SigScheme(TPMT_SIG_SCHEME *sigScheme)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (sigScheme->details.any.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_StartAuthSession(StartAuthSession_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->authHash == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_Create(Create_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&in->inPublic.publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_Load(Load_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&in->inPublic.publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_LoadExternal(LoadExternal_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&in->inPublic.publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_CreateLoaded(CreateLoaded_In *in)
{
    TPM_RC rc = 0;
    uint32_t size = sizeof(in->inPublic.t.buffer);
    uint8_t *buffer = in->inPublic.t.buffer;
    TPMT_PUBLIC publicArea;

    if (rc == 0) {
	rc = TSS_TPMT_PUBLIC_Unmarshalu(&publicArea, &buffer, &size, TRUE);
    }

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_Import(Import_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&in->objectPublic.publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_RSA_Encrypt(RSA_Encrypt_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->inScheme.details.anySig.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_RSA_Decrypt(RSA_Decrypt_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->inScheme.details.anySig.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_ECC_Encrypt(ECC_Encrypt_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->inScheme.details.mgf1.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_ECC_Decrypt(ECC_Decrypt_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->inScheme.details.mgf1.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_Hash(Hash_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_HMAC(HMAC_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_HMAC_Start(HMAC_Start_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_HashSequenceStart(HashSequenceStart_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_Certify(Certify_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_CertifyX509(CertifyX509_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_CertifyCreation(CertifyCreation_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_Quote(Quote_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_GetSessionAuditDigest(GetSessionAuditDigest_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_GetCommandAuditDigest(GetCommandAuditDigest_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_GetTime(GetTime_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_VerifySignature(VerifySignature_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->signature.signature.any.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_Sign(Sign_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

static TPM_RC TSS_CH_SetCommandCodeAuditStatus(SetCommandCodeAuditStatus_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->auditAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_PolicySigned(PolicySigned_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->auth.signature.any.hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_CreatePrimary(CreatePrimary_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_PublicArea(&in->inPublic.publicArea);
    }

    return rc;
}

static TPM_RC TSS_CH_SetPrimaryPolicy(SetPrimaryPolicy_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->hashAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_NV_DefineSpace(NV_DefineSpace_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	if (in->publicInfo.nvPublic.nameAlg == TPM_ALG_SHA1) {
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }

    return rc;
}

static TPM_RC TSS_CH_NV_Certify(NV_Certify_In *in)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_CheckSha1_SigScheme(&in->inScheme);
    }

    return rc;
}

#endif /* TPM_TSS_NODEPRECATEDALGS */

typedef struct TSS_TABLE {
    TPM_CC 				commandCode;
    TSS_PreProcessFunction_t		preProcessFunction;
    TSS_ChangeAuthFunction_t		changeAuthFunction;
    TSS_PostProcessFunction_t 		postProcessFunction;
} TSS_TABLE;

/* This table indexes from the command to pre- and post- processing functions.  A missing entry is
   not an error, and indicates a command with no functions. */

static const TSS_TABLE tssTable [] = {

    {TPM_CC_Startup, NULL, NULL, NULL},
    {TPM_CC_Shutdown, NULL, NULL, NULL},
    {TPM_CC_SelfTest, NULL, NULL, NULL},
    {TPM_CC_IncrementalSelfTest, NULL, NULL, NULL},
    {TPM_CC_GetTestResult, NULL, NULL, NULL},
    {TPM_CC_StartAuthSession, (TSS_PreProcessFunction_t)TSS_PR_StartAuthSession, NULL, (TSS_PostProcessFunction_t)TSS_PO_StartAuthSession},
    {TPM_CC_PolicyRestart, NULL, NULL, NULL},
    {TPM_CC_Create, NULL, NULL, NULL},
    {TPM_CC_Load, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_Load},
    {TPM_CC_LoadExternal, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_LoadExternal},
    {TPM_CC_ReadPublic, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_ReadPublic},
    {TPM_CC_ActivateCredential, NULL, NULL, NULL},
    {TPM_CC_MakeCredential, NULL, NULL, NULL},
    {TPM_CC_Unseal, NULL, NULL, NULL},
    {TPM_CC_ObjectChangeAuth, NULL, NULL, NULL},
    {TPM_CC_CreateLoaded, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_CreateLoaded},
    {TPM_CC_Duplicate, NULL, NULL, NULL},
    {TPM_CC_Rewrap, NULL, NULL, NULL},
    {TPM_CC_Import, NULL, NULL, NULL},
    {TPM_CC_RSA_Encrypt, NULL, NULL, NULL},
    {TPM_CC_RSA_Decrypt, NULL, NULL, NULL},
    {TPM_CC_ECDH_KeyGen, NULL, NULL, NULL},
    {TPM_CC_ECDH_ZGen, NULL, NULL, NULL},
    {TPM_CC_ECC_Encrypt, NULL, NULL, NULL},
    {TPM_CC_ECC_Decrypt, NULL, NULL, NULL},
    {TPM_CC_ECC_Parameters, NULL, NULL, NULL},
    {TPM_CC_ZGen_2Phase, NULL, NULL, NULL},
    {TPM_CC_EncryptDecrypt, NULL, NULL, NULL},
    {TPM_CC_EncryptDecrypt2, NULL, NULL, NULL},
    {TPM_CC_Hash, NULL, NULL, NULL},
    {TPM_CC_HMAC, NULL, NULL, NULL},
    {TPM_CC_GetRandom, NULL, NULL, NULL},
    {TPM_CC_StirRandom, NULL, NULL, NULL},
    {TPM_CC_HMAC_Start, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_HMAC_Start},
    {TPM_CC_HashSequenceStart, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_HashSequenceStart},
    {TPM_CC_SequenceUpdate, NULL, NULL, NULL},
    {TPM_CC_SequenceComplete, NULL,NULL, (TSS_PostProcessFunction_t)TSS_PO_SequenceComplete},
    {TPM_CC_EventSequenceComplete, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_EventSequenceComplete},
    {TPM_CC_Certify, NULL, NULL, NULL},
    {TPM_CC_CertifyX509, NULL, NULL, NULL},
    {TPM_CC_CertifyCreation, NULL, NULL, NULL},
    {TPM_CC_Quote, NULL, NULL, NULL},
    {TPM_CC_GetSessionAuditDigest, NULL, NULL, NULL},
    {TPM_CC_GetCommandAuditDigest, NULL, NULL, NULL},
    {TPM_CC_GetTime, NULL, NULL, NULL},
    {TPM_CC_Commit, NULL, NULL, NULL},
    {TPM_CC_EC_Ephemeral, NULL, NULL, NULL},
    {TPM_CC_VerifySignature, NULL, NULL, NULL},
    {TPM_CC_Sign, NULL, NULL, NULL},
    {TPM_CC_SetCommandCodeAuditStatus, NULL, NULL, NULL},
    {TPM_CC_PCR_Extend, NULL, NULL, NULL},
    {TPM_CC_PCR_Event, NULL, NULL, NULL},
    {TPM_CC_PCR_Read, NULL, NULL, NULL},
    {TPM_CC_PCR_Allocate, NULL, NULL, NULL},
    {TPM_CC_PCR_SetAuthPolicy, NULL, NULL, NULL},
    {TPM_CC_PCR_SetAuthValue, NULL, NULL, NULL},
    {TPM_CC_PCR_Reset, NULL, NULL, NULL},
    {TPM_CC_PolicySigned, NULL, NULL, NULL},
    {TPM_CC_PolicySecret, NULL, NULL, NULL},
    {TPM_CC_PolicyTicket, NULL, NULL, NULL},
    {TPM_CC_PolicyOR, NULL, NULL, NULL},
    {TPM_CC_PolicyPCR, NULL, NULL, NULL},
    {TPM_CC_PolicyLocality, NULL, NULL, NULL},
    {TPM_CC_PolicyNV, NULL, NULL, NULL},
    {TPM_CC_PolicyAuthorizeNV, NULL, NULL, NULL},
    {TPM_CC_PolicyCounterTimer, NULL, NULL, NULL},
    {TPM_CC_PolicyCommandCode, NULL, NULL, NULL},
    {TPM_CC_PolicyPhysicalPresence, NULL, NULL, NULL},
    {TPM_CC_PolicyCpHash, NULL, NULL, NULL},
    {TPM_CC_PolicyNameHash, NULL, NULL, NULL},
    {TPM_CC_PolicyDuplicationSelect, NULL, NULL, NULL},
    {TPM_CC_PolicyAuthorize, NULL, NULL, NULL},
    {TPM_CC_PolicyAuthValue, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_PolicyAuthValue},
    {TPM_CC_PolicyPassword, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_PolicyPassword},
    {TPM_CC_PolicyGetDigest, NULL, NULL, NULL},
    {TPM_CC_PolicyNvWritten, NULL, NULL, NULL},
    {TPM_CC_PolicyTemplate, NULL, NULL, NULL},
    {TPM_CC_CreatePrimary, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_CreatePrimary},
    {TPM_CC_HierarchyControl, NULL, NULL, NULL},
    {TPM_CC_SetPrimaryPolicy, NULL, NULL, NULL},
    {TPM_CC_ChangePPS, NULL, NULL, NULL},
    {TPM_CC_ChangeEPS, NULL, NULL, NULL},
    {TPM_CC_Clear, NULL, NULL, NULL},
    {TPM_CC_ClearControl, NULL, NULL, NULL},
    {TPM_CC_HierarchyChangeAuth, NULL, (TSS_ChangeAuthFunction_t)TSS_CA_HierarchyChangeAuth, NULL},
    {TPM_CC_DictionaryAttackLockReset, NULL, NULL, NULL},
    {TPM_CC_DictionaryAttackParameters, NULL, NULL, NULL},
    {TPM_CC_PP_Commands, NULL, NULL, NULL},
    {TPM_CC_SetAlgorithmSet, NULL, NULL, NULL},
    {TPM_CC_ContextSave, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_ContextSave},
    {TPM_CC_ContextLoad, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_ContextLoad},
    {TPM_CC_FlushContext, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_FlushContext},
    {TPM_CC_EvictControl, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_EvictControl},
    {TPM_CC_ReadClock, NULL, NULL, NULL},
    {TPM_CC_ClockSet, NULL, NULL, NULL},
    {TPM_CC_ClockRateAdjust, NULL, NULL, NULL},
    {TPM_CC_GetCapability, NULL, NULL, NULL},
    {TPM_CC_TestParms, NULL, NULL, NULL},
    {TPM_CC_NV_DefineSpace, (TSS_PreProcessFunction_t)TSS_PR_NV_DefineSpace, NULL,  (TSS_PostProcessFunction_t)TSS_PO_NV_DefineSpace},
    {TPM_CC_NV_UndefineSpace, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_UndefineSpace},
    {TPM_CC_NV_UndefineSpaceSpecial, NULL, (TSS_ChangeAuthFunction_t)TSS_CA_NV_UndefineSpaceSpecial, (TSS_PostProcessFunction_t)TSS_PO_NV_UndefineSpaceSpecial},
    {TPM_CC_NV_ReadPublic, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_ReadPublic},
    {TPM_CC_NV_Write, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_Write},
    {TPM_CC_NV_Increment, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_Write},
    {TPM_CC_NV_Extend, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_Write},
    {TPM_CC_NV_SetBits, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_Write},
    {TPM_CC_NV_WriteLock, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_WriteLock},
    {TPM_CC_NV_GlobalWriteLock, NULL, NULL, NULL},
    {TPM_CC_NV_Read, NULL, NULL, NULL},
    {TPM_CC_NV_ReadLock, NULL, NULL, (TSS_PostProcessFunction_t)TSS_PO_NV_ReadLock},
    {TPM_CC_NV_ChangeAuth, NULL, (TSS_ChangeAuthFunction_t)TSS_CA_NV_ChangeAuth, NULL},
    {TPM_CC_NV_Certify, NULL, NULL, NULL}
};

#ifdef TPM_TSS_NODEPRECATEDALGS

/* This table indexes from the command to algorith check processing functions.  A missing entry is
   not an error, and indicates a command with no functions. */

typedef struct TSS_CH_TABLE {
    TPM_CC 				commandCode;
    TSS_CheckParametersFunction_t	checkParametersFunction;
} TSS_CH_TABLE;

static const TSS_CH_TABLE tssChTable [] = {

    {TPM_CC_Startup, NULL},
    {TPM_CC_Shutdown, NULL},
    {TPM_CC_SelfTest, NULL},
    {TPM_CC_IncrementalSelfTest, NULL},
    {TPM_CC_GetTestResult, NULL},
    {TPM_CC_StartAuthSession, (TSS_CheckParametersFunction_t)TSS_CH_StartAuthSession},
    {TPM_CC_PolicyRestart, NULL},
    {TPM_CC_Create, (TSS_CheckParametersFunction_t)TSS_CH_Create},
    {TPM_CC_Load, (TSS_CheckParametersFunction_t)TSS_CH_Load},
    {TPM_CC_LoadExternal, (TSS_CheckParametersFunction_t)TSS_CH_LoadExternal},
    {TPM_CC_ReadPublic, NULL},
    {TPM_CC_ActivateCredential, NULL},
    {TPM_CC_MakeCredential, NULL},
    {TPM_CC_Unseal, NULL},
    {TPM_CC_ObjectChangeAuth, NULL},
    {TPM_CC_CreateLoaded, (TSS_CheckParametersFunction_t)TSS_CH_CreateLoaded},
    {TPM_CC_Duplicate, NULL},
    {TPM_CC_Rewrap, NULL},
    {TPM_CC_Import, (TSS_CheckParametersFunction_t)TSS_CH_Import},
    {TPM_CC_RSA_Encrypt, (TSS_CheckParametersFunction_t)TSS_CH_RSA_Encrypt},
    {TPM_CC_RSA_Decrypt, (TSS_CheckParametersFunction_t)TSS_CH_RSA_Decrypt},
    {TPM_CC_ECDH_KeyGen, NULL},
    {TPM_CC_ECDH_ZGen, NULL},
    {TPM_CC_ECC_Encrypt, (TSS_CheckParametersFunction_t)TSS_CH_ECC_Encrypt},
    {TPM_CC_ECC_Decrypt, (TSS_CheckParametersFunction_t)TSS_CH_ECC_Decrypt},
    {TPM_CC_ECC_Parameters, NULL},
    {TPM_CC_ZGen_2Phase, NULL},
    {TPM_CC_EncryptDecrypt, NULL},
    {TPM_CC_EncryptDecrypt2, NULL},
    {TPM_CC_Hash, (TSS_CheckParametersFunction_t)TSS_CH_Hash},
    {TPM_CC_HMAC, (TSS_CheckParametersFunction_t)TSS_CH_HMAC},
    {TPM_CC_GetRandom, NULL},
    {TPM_CC_StirRandom, NULL},
    {TPM_CC_HMAC_Start, (TSS_CheckParametersFunction_t)TSS_CH_HMAC_Start},
    {TPM_CC_HashSequenceStart, (TSS_CheckParametersFunction_t)TSS_CH_HashSequenceStart},
    {TPM_CC_SequenceUpdate, NULL},
    {TPM_CC_SequenceComplete, NULL},
    {TPM_CC_EventSequenceComplete, NULL},
    {TPM_CC_Certify, (TSS_CheckParametersFunction_t)TSS_CH_Certify},
    {TPM_CC_CertifyX509, (TSS_CheckParametersFunction_t)TSS_CH_CertifyX509},
    {TPM_CC_CertifyCreation, (TSS_CheckParametersFunction_t)TSS_CH_CertifyCreation},
    {TPM_CC_Quote, (TSS_CheckParametersFunction_t)TSS_CH_Quote},
    {TPM_CC_GetSessionAuditDigest, (TSS_CheckParametersFunction_t)TSS_CH_GetSessionAuditDigest},
    {TPM_CC_GetCommandAuditDigest, (TSS_CheckParametersFunction_t)TSS_CH_GetCommandAuditDigest},
    {TPM_CC_GetTime, (TSS_CheckParametersFunction_t)TSS_CH_GetTime},
    {TPM_CC_Commit, NULL},
    {TPM_CC_EC_Ephemeral, NULL},
    {TPM_CC_VerifySignature, (TSS_CheckParametersFunction_t)TSS_CH_VerifySignature},
    {TPM_CC_Sign, (TSS_CheckParametersFunction_t)TSS_CH_Sign},
    {TPM_CC_SetCommandCodeAuditStatus, (TSS_CheckParametersFunction_t)TSS_CH_SetCommandCodeAuditStatus},
    {TPM_CC_PCR_Extend, NULL},
    {TPM_CC_PCR_Event, NULL},
    {TPM_CC_PCR_Read, NULL},
    {TPM_CC_PCR_Allocate, NULL},
    {TPM_CC_PCR_SetAuthPolicy, NULL},
    {TPM_CC_PCR_SetAuthValue, NULL},
    {TPM_CC_PCR_Reset, NULL},
    {TPM_CC_PolicySigned, (TSS_CheckParametersFunction_t)TSS_CH_PolicySigned},
    {TPM_CC_PolicySecret, NULL},
    {TPM_CC_PolicyTicket, NULL},
    {TPM_CC_PolicyOR, NULL},
    {TPM_CC_PolicyPCR, NULL},
    {TPM_CC_PolicyLocality, NULL},
    {TPM_CC_PolicyNV, NULL},
    {TPM_CC_PolicyAuthorizeNV, NULL},
    {TPM_CC_PolicyCounterTimer, NULL},
    {TPM_CC_PolicyCommandCode, NULL},
    {TPM_CC_PolicyPhysicalPresence, NULL},
    {TPM_CC_PolicyCpHash, NULL},
    {TPM_CC_PolicyNameHash, NULL},
    {TPM_CC_PolicyDuplicationSelect, NULL},
    {TPM_CC_PolicyAuthorize, NULL},
    {TPM_CC_PolicyAuthValue, NULL},
    {TPM_CC_PolicyPassword, NULL},
    {TPM_CC_PolicyGetDigest, NULL},
    {TPM_CC_PolicyNvWritten, NULL},
    {TPM_CC_PolicyTemplate, NULL},
    {TPM_CC_CreatePrimary, (TSS_CheckParametersFunction_t)TSS_CH_CreatePrimary},
    {TPM_CC_HierarchyControl, NULL},
    {TPM_CC_SetPrimaryPolicy, (TSS_CheckParametersFunction_t)TSS_CH_SetPrimaryPolicy},
    {TPM_CC_ChangePPS, NULL},
    {TPM_CC_ChangeEPS, NULL},
    {TPM_CC_Clear, NULL},
    {TPM_CC_ClearControl, NULL},
    {TPM_CC_HierarchyChangeAuth, NULL},
    {TPM_CC_DictionaryAttackLockReset, NULL},
    {TPM_CC_DictionaryAttackParameters, NULL},
    {TPM_CC_PP_Commands, NULL},
    {TPM_CC_SetAlgorithmSet, NULL},
    {TPM_CC_ContextSave, NULL},
    {TPM_CC_ContextLoad, NULL},
    {TPM_CC_FlushContext, NULL},
    {TPM_CC_EvictControl, NULL},
    {TPM_CC_ReadClock, NULL},
    {TPM_CC_ClockSet, NULL},
    {TPM_CC_ClockRateAdjust, NULL},
    {TPM_CC_GetCapability, NULL},
    {TPM_CC_TestParms, NULL},
    {TPM_CC_NV_DefineSpace, (TSS_CheckParametersFunction_t)TSS_CH_NV_DefineSpace},
    {TPM_CC_NV_UndefineSpace, NULL},
    {TPM_CC_NV_UndefineSpaceSpecial, NULL},
    {TPM_CC_NV_ReadPublic, NULL},
    {TPM_CC_NV_Write, NULL},
    {TPM_CC_NV_Increment, NULL},
    {TPM_CC_NV_Extend, NULL},
    {TPM_CC_NV_SetBits, NULL},
    {TPM_CC_NV_WriteLock, NULL},
    {TPM_CC_NV_GlobalWriteLock, NULL},
    {TPM_CC_NV_Read, NULL},
    {TPM_CC_NV_ReadLock, NULL},
    {TPM_CC_NV_ChangeAuth, NULL},
    {TPM_CC_NV_Certify, (TSS_CheckParametersFunction_t)TSS_CH_NV_Certify}
};

#endif  /* TPM_TSS_NODEPRECATEDALGS */

#ifndef TPM_TSS_NO_PRINT

typedef void (*TSS_InPrintFunction_t)(COMMAND_PARAMETERS *in, unsigned int indent);

typedef struct TSS_PRINT_TABLE {
    TPM_CC 			commandCode;
    TSS_InPrintFunction_t	inPrintFunction;
} TSS_PRINT_TABLE;

/* This table indexes from the command to print functions.  A missing entry is
   not an error, and indicates a command with no function. */

static const TSS_PRINT_TABLE tssPrintTable [] = {
				 
    {TPM_CC_Startup, (TSS_InPrintFunction_t)Startup_In_Print},
    {TPM_CC_Shutdown, (TSS_InPrintFunction_t)Shutdown_In_Print},
    {TPM_CC_SelfTest, (TSS_InPrintFunction_t)SelfTest_In_Print},
    {TPM_CC_IncrementalSelfTest, (TSS_InPrintFunction_t)IncrementalSelfTest_In_Print},
    {TPM_CC_GetTestResult, NULL},
    {TPM_CC_StartAuthSession, (TSS_InPrintFunction_t)StartAuthSession_In_Print},
    {TPM_CC_PolicyRestart, (TSS_InPrintFunction_t)PolicyRestart_In_Print},
    {TPM_CC_Create,(TSS_InPrintFunction_t)Create_In_Print},
    {TPM_CC_Load, (TSS_InPrintFunction_t)Load_In_Print},
    {TPM_CC_LoadExternal, (TSS_InPrintFunction_t)LoadExternal_In_Print},
    {TPM_CC_ReadPublic, (TSS_InPrintFunction_t)ReadPublic_In_Print},
    {TPM_CC_ActivateCredential, (TSS_InPrintFunction_t)ActivateCredential_In_Print},
    {TPM_CC_MakeCredential, (TSS_InPrintFunction_t)MakeCredential_In_Print},
    {TPM_CC_Unseal, (TSS_InPrintFunction_t)Unseal_In_Print},
    {TPM_CC_ObjectChangeAuth, (TSS_InPrintFunction_t)ObjectChangeAuth_In_Print},
    {TPM_CC_CreateLoaded, (TSS_InPrintFunction_t)CreateLoaded_In_Print},
    {TPM_CC_Duplicate, (TSS_InPrintFunction_t)Duplicate_In_Print},
    {TPM_CC_Rewrap, (TSS_InPrintFunction_t)Rewrap_In_Print},
    {TPM_CC_Import, (TSS_InPrintFunction_t)Import_In_Print},
    {TPM_CC_RSA_Encrypt, (TSS_InPrintFunction_t)RSA_Encrypt_In_Print},
    {TPM_CC_RSA_Decrypt, (TSS_InPrintFunction_t)RSA_Decrypt_In_Print},
    {TPM_CC_ECDH_KeyGen, (TSS_InPrintFunction_t)ECDH_KeyGen_In_Print},
    {TPM_CC_ECDH_ZGen, (TSS_InPrintFunction_t)ECDH_ZGen_In_Print},
    {TPM_CC_ECC_Encrypt, (TSS_InPrintFunction_t)ECC_Encrypt_In_Print},
    {TPM_CC_ECC_Decrypt, (TSS_InPrintFunction_t)ECC_Decrypt_In_Print},
    {TPM_CC_ECC_Parameters, (TSS_InPrintFunction_t)ECC_Parameters_In_Print},
    {TPM_CC_ZGen_2Phase, (TSS_InPrintFunction_t)ZGen_2Phase_In_Print},
    {TPM_CC_EncryptDecrypt, (TSS_InPrintFunction_t)EncryptDecrypt_In_Print},
    {TPM_CC_EncryptDecrypt2, (TSS_InPrintFunction_t)EncryptDecrypt2_In_Print},
    {TPM_CC_Hash, (TSS_InPrintFunction_t)Hash_In_Print},
    {TPM_CC_HMAC, (TSS_InPrintFunction_t)HMAC_In_Print},
    {TPM_CC_GetRandom, (TSS_InPrintFunction_t)GetRandom_In_Print},
    {TPM_CC_StirRandom, (TSS_InPrintFunction_t)StirRandom_In_Print},
    {TPM_CC_HMAC_Start, (TSS_InPrintFunction_t)HMAC_Start_In_Print},
    {TPM_CC_HashSequenceStart, (TSS_InPrintFunction_t)HashSequenceStart_In_Print},
    {TPM_CC_SequenceUpdate, (TSS_InPrintFunction_t)SequenceUpdate_In_Print},
    {TPM_CC_SequenceComplete, (TSS_InPrintFunction_t)SequenceComplete_In_Print},
    {TPM_CC_EventSequenceComplete, (TSS_InPrintFunction_t)EventSequenceComplete_In_Print},
    {TPM_CC_Certify, (TSS_InPrintFunction_t)Certify_In_Print},
    {TPM_CC_CertifyX509, (TSS_InPrintFunction_t)CertifyX509_In_Print},
    {TPM_CC_CertifyCreation, (TSS_InPrintFunction_t)CertifyCreation_In_Print},
    {TPM_CC_Quote, (TSS_InPrintFunction_t)Quote_In_Print},
    {TPM_CC_GetSessionAuditDigest, (TSS_InPrintFunction_t)GetSessionAuditDigest_In_Print},
    {TPM_CC_GetCommandAuditDigest, (TSS_InPrintFunction_t)GetCommandAuditDigest_In_Print},
    {TPM_CC_GetTime, (TSS_InPrintFunction_t)GetTime_In_Print},
    {TPM_CC_Commit, (TSS_InPrintFunction_t)Commit_In_Print},
    {TPM_CC_EC_Ephemeral, (TSS_InPrintFunction_t)EC_Ephemeral_In_Print},
    {TPM_CC_VerifySignature, (TSS_InPrintFunction_t)VerifySignature_In_Print},
    {TPM_CC_Sign, (TSS_InPrintFunction_t)Sign_In_Print},
    {TPM_CC_SetCommandCodeAuditStatus, (TSS_InPrintFunction_t)SetCommandCodeAuditStatus_In_Print},
    {TPM_CC_PCR_Extend, (TSS_InPrintFunction_t)PCR_Extend_In_Print},
    {TPM_CC_PCR_Event, (TSS_InPrintFunction_t)PCR_Event_In_Print},
    {TPM_CC_PCR_Read, (TSS_InPrintFunction_t)PCR_Read_In_Print},
    {TPM_CC_PCR_Allocate, (TSS_InPrintFunction_t)PCR_Allocate_In_Print},
    {TPM_CC_PCR_SetAuthPolicy, (TSS_InPrintFunction_t)PCR_SetAuthPolicy_In_Print},
    {TPM_CC_PCR_SetAuthValue, (TSS_InPrintFunction_t)PCR_SetAuthValue_In_Print},
    {TPM_CC_PCR_Reset, (TSS_InPrintFunction_t)PCR_Reset_In_Print},
    {TPM_CC_PolicySigned, (TSS_InPrintFunction_t)PolicySigned_In_Print},
    {TPM_CC_PolicySecret, (TSS_InPrintFunction_t)PolicySecret_In_Print},
    {TPM_CC_PolicyTicket, (TSS_InPrintFunction_t)PolicyTicket_In_Print},
    {TPM_CC_PolicyOR, (TSS_InPrintFunction_t)PolicyOR_In_Print},
    {TPM_CC_PolicyPCR, (TSS_InPrintFunction_t)PolicyPCR_In_Print},
    {TPM_CC_PolicyLocality, (TSS_InPrintFunction_t)PolicyLocality_In_Print},
    {TPM_CC_PolicyNV, (TSS_InPrintFunction_t)PolicyNV_In_Print},
    {TPM_CC_PolicyAuthorizeNV, (TSS_InPrintFunction_t)PolicyAuthorizeNV_In_Print},
    {TPM_CC_PolicyCounterTimer, (TSS_InPrintFunction_t)PolicyCounterTimer_In_Print},
    {TPM_CC_PolicyCommandCode, (TSS_InPrintFunction_t)PolicyCommandCode_In_Print},
    {TPM_CC_PolicyPhysicalPresence, (TSS_InPrintFunction_t)PolicyPhysicalPresence_In_Print},
    {TPM_CC_PolicyCpHash, (TSS_InPrintFunction_t)PolicyCpHash_In_Print},
    {TPM_CC_PolicyNameHash, (TSS_InPrintFunction_t)PolicyNameHash_In_Print},
    {TPM_CC_PolicyDuplicationSelect, (TSS_InPrintFunction_t)PolicyDuplicationSelect_In_Print},
    {TPM_CC_PolicyAuthorize, (TSS_InPrintFunction_t)PolicyAuthorize_In_Print},
    {TPM_CC_PolicyAuthValue, (TSS_InPrintFunction_t)PolicyAuthValue_In_Print},
    {TPM_CC_PolicyPassword, (TSS_InPrintFunction_t)PolicyPassword_In_Print},
    {TPM_CC_PolicyGetDigest, (TSS_InPrintFunction_t)PolicyGetDigest_In_Print},
    {TPM_CC_PolicyNvWritten, (TSS_InPrintFunction_t)PolicyNvWritten_In_Print},
    {TPM_CC_PolicyTemplate, (TSS_InPrintFunction_t)PolicyTemplate_In_Print},
    {TPM_CC_CreatePrimary, (TSS_InPrintFunction_t)CreatePrimary_In_Print},
    {TPM_CC_HierarchyControl, (TSS_InPrintFunction_t)HierarchyControl_In_Print},
    {TPM_CC_SetPrimaryPolicy, (TSS_InPrintFunction_t)SetPrimaryPolicy_In_Print},
    {TPM_CC_ChangePPS, (TSS_InPrintFunction_t)ChangePPS_In_Print},
    {TPM_CC_ChangeEPS, (TSS_InPrintFunction_t)ChangeEPS_In_Print},
    {TPM_CC_Clear, (TSS_InPrintFunction_t)Clear_In_Print},
    {TPM_CC_ClearControl, (TSS_InPrintFunction_t)ClearControl_In_Print},
    {TPM_CC_HierarchyChangeAuth, (TSS_InPrintFunction_t)HierarchyChangeAuth_In_Print},
    {TPM_CC_DictionaryAttackLockReset, (TSS_InPrintFunction_t)DictionaryAttackLockReset_In_Print},
    {TPM_CC_DictionaryAttackParameters, (TSS_InPrintFunction_t)DictionaryAttackParameters_In_Print},
    {TPM_CC_PP_Commands, (TSS_InPrintFunction_t)PP_Commands_In_Print},
    {TPM_CC_SetAlgorithmSet, (TSS_InPrintFunction_t)SetAlgorithmSet_In_Print},
    {TPM_CC_ContextSave, (TSS_InPrintFunction_t)ContextSave_In_Print},
    {TPM_CC_ContextLoad, (TSS_InPrintFunction_t)ContextLoad_In_Print},
    {TPM_CC_FlushContext, (TSS_InPrintFunction_t)FlushContext_In_Print},
    {TPM_CC_EvictControl, (TSS_InPrintFunction_t)EvictControl_In_Print},
    {TPM_CC_ReadClock, (TSS_InPrintFunction_t)NULL},
    {TPM_CC_ClockSet, (TSS_InPrintFunction_t)ClockSet_In_Print},
    {TPM_CC_ClockRateAdjust, (TSS_InPrintFunction_t)ClockRateAdjust_In_Print},
    {TPM_CC_GetCapability, (TSS_InPrintFunction_t)GetCapability_In_Print},
    {TPM_CC_TestParms, (TSS_InPrintFunction_t)TestParms_In_Print},
    {TPM_CC_NV_DefineSpace, (TSS_InPrintFunction_t)NV_DefineSpace_In_Print},
    {TPM_CC_NV_UndefineSpace, (TSS_InPrintFunction_t)NV_UndefineSpace_In_Print},
    {TPM_CC_NV_UndefineSpaceSpecial, (TSS_InPrintFunction_t)NV_UndefineSpaceSpecial_In_Print},
    {TPM_CC_NV_ReadPublic, (TSS_InPrintFunction_t)NV_ReadPublic_In_Print},
    {TPM_CC_NV_Write, (TSS_InPrintFunction_t)NV_Write_In_Print},
    {TPM_CC_NV_Increment, (TSS_InPrintFunction_t)NV_Increment_In_Print},
    {TPM_CC_NV_Extend, (TSS_InPrintFunction_t)NV_Extend_In_Print},
    {TPM_CC_NV_SetBits, (TSS_InPrintFunction_t)NV_SetBits_In_Print},
    {TPM_CC_NV_WriteLock, (TSS_InPrintFunction_t)NV_WriteLock_In_Print},
    {TPM_CC_NV_GlobalWriteLock, (TSS_InPrintFunction_t)NV_GlobalWriteLock_In_Print},
    {TPM_CC_NV_Read, (TSS_InPrintFunction_t)NV_Read_In_Print},
    {TPM_CC_NV_ReadLock, (TSS_InPrintFunction_t)NV_ReadLock_In_Print},
    {TPM_CC_NV_ChangeAuth, (TSS_InPrintFunction_t)NV_ChangeAuth_In_Print},
    {TPM_CC_NV_Certify, (TSS_InPrintFunction_t)NV_Certify_In_Print}
};

#endif /* TPM_TSS_NO_PRINT */

/* local prototypes */

static TPM_RC TSS_Execute_valist(TSS_CONTEXT *tssContext,
				 COMMAND_PARAMETERS *in,
				 va_list ap);


static TPM_RC TSS_PwapSession_Set(TPMS_AUTH_COMMAND *authCommand,
				  const char *password);
static TPM_RC TSS_PwapSession_Verify(TPMS_AUTH_RESPONSE *authResponse);

static TPM_RC TSS_HmacSession_GetContext(struct TSS_HMAC_CONTEXT **session);
static void   TSS_HmacSession_InitContext(struct TSS_HMAC_CONTEXT *session);
static void   TSS_HmacSession_FreeContext(struct TSS_HMAC_CONTEXT *session);

#ifndef TPM_TSS_NOCRYPTO
static TPM_RC TSS_HmacSession_SetSessionKey(TSS_CONTEXT *tssContext,
					    struct TSS_HMAC_CONTEXT *session,
					    TPM2B_DIGEST *salt,
					    TPMI_DH_ENTITY bind,
					    TPM2B_AUTH *bindAuthValue);
static TPM_RC TSS_HmacSession_SetNonceCaller(struct TSS_HMAC_CONTEXT *session,
					     TPMS_AUTH_COMMAND 	*authC);
static TPM_RC TSS_HmacSession_SetHmacKey(TSS_CONTEXT *tssContext,
					 struct TSS_HMAC_CONTEXT *session,
					 size_t handleNumber,
					 const char *password);
#endif	/* TPM_TSS_NOCRYPTO */
static TPM_RC TSS_HmacSession_SetHMAC(TSS_AUTH_CONTEXT *tssAuthContext,
				      struct TSS_HMAC_CONTEXT *session[],
				      TPMS_AUTH_COMMAND *authCommand[],
				      TPMI_SH_AUTH_SESSION sessionHandle[],
				      unsigned int sessionAttributes[],
				      const char *password[],
				      TPM2B_NAME *name0,		  
				      TPM2B_NAME *name1,		  
				      TPM2B_NAME *name2);
#ifndef TPM_TSS_NOCRYPTO
static TPM_RC TSS_HmacSession_Verify(TSS_AUTH_CONTEXT *tssAuthContext,
				     struct TSS_HMAC_CONTEXT *session,
				     TPMS_AUTH_RESPONSE *authResponse);
#endif	/* TPM_TSS_NOCRYPTO */
static TPM_RC TSS_HmacSession_Continue(TSS_CONTEXT *tssContext,
				       struct TSS_HMAC_CONTEXT *session,
				       TPMS_AUTH_RESPONSE *authR);


static TPM_RC TSS_HmacSession_SaveSession(TSS_CONTEXT *tssContext,
					  struct TSS_HMAC_CONTEXT *session);
static TPM_RC TSS_HmacSession_LoadSession(TSS_CONTEXT *tssContext,
					  struct TSS_HMAC_CONTEXT *session,
					  TPMI_SH_AUTH_SESSION	sessionHandle);
#ifdef TPM_TSS_NOFILE
static TPM_RC TSS_HmacSession_SaveData(TSS_CONTEXT *tssContext,
				       TPMI_SH_AUTH_SESSION sessionHandle,
				       uint32_t outLength,
				       uint8_t *outBuffer);
static TPM_RC TSS_HmacSession_LoadData(TSS_CONTEXT *tssContext,
				       uint32_t *inLength, uint8_t **inData,
				       TPMI_SH_AUTH_SESSION sessionHandle);
static TPM_RC TSS_HmacSession_DeleteData(TSS_CONTEXT *tssContext,
					 TPMI_SH_AUTH_SESSION sessionHandle);
static TPM_RC TSS_HmacSession_GetSlotForHandle(TSS_CONTEXT *tssContext,
					       size_t *slotIndex,
					       TPMI_SH_AUTH_SESSION sessionHandle);
#endif
static TPM_RC TSS_HmacSession_Marshal(struct TSS_HMAC_CONTEXT *source,
				      uint16_t *written, uint8_t **buffer, uint32_t *size);
static TPM_RC TSS_HmacSession_Unmarshal(struct TSS_HMAC_CONTEXT *target,
					uint8_t **buffer, uint32_t *size);

static TPM_RC TSS_Name_GetAllNames(TSS_CONTEXT *tssContext,
				   TPM2B_NAME **names);
static TPM_RC TSS_Name_GetName(TSS_CONTEXT *tssContext,
			       TPM2B_NAME *name,
			       TPM_HANDLE  handle);
static TPM_RC TSS_Name_Store(TSS_CONTEXT *tssContext,
			     TPM2B_NAME *name,
			     TPM_HANDLE handle,
			     const char *string);
static TPM_RC TSS_Name_Load(TSS_CONTEXT *tssContext,
			    TPM2B_NAME *name,
			    TPM_HANDLE handle,
			    const char *string);
static TPM_RC TSS_Name_Copy(TSS_CONTEXT *tssContext,
			    TPM_HANDLE outHandle,
			    const char *outString,
			    TPM_HANDLE inHandle,
			    const char *inString);
static TPM_RC TSS_Public_Store(TSS_CONTEXT *tssContext,
			       TPM2B_PUBLIC *public,
			       TPM_HANDLE handle,
			       const char *string);
static TPM_RC TSS_Public_Load(TSS_CONTEXT *tssContext,
			      TPM2B_PUBLIC *public,
			      TPM_HANDLE handle,
			      const char *string);
static TPM_RC TSS_Public_Copy(TSS_CONTEXT *tssContext,
			      TPM_HANDLE outHandle,
			      const char *outString,
			      TPM_HANDLE inHandle,
			      const char *inString);
#ifdef TPM_TSS_NOFILE
static TPM_RC TSS_ObjectPublic_GetSlotForHandle(TSS_CONTEXT *tssContext,
						size_t *slotIndex,
						TPM_HANDLE handle);
static TPM_RC TSS_ObjectPublic_DeleteData(TSS_CONTEXT *tssContext, TPM_HANDLE handle);
#endif
static TPM_RC TSS_DeleteHandle(TSS_CONTEXT *tssContext,
			       TPM_HANDLE handle);
#ifndef TPM_TSS_NOCRYPTO
static TPM_RC TSS_ObjectPublic_GetName(TPM2B_NAME *name,
				       TPMT_PUBLIC *tpmtPublic);

static TPM_RC TSS_NVPublic_Store(TSS_CONTEXT *tssContext,
				 TPMS_NV_PUBLIC *nvPublic,
				 TPMI_RH_NV_INDEX handle);
static TPM_RC TSS_NVPublic_Load(TSS_CONTEXT *tssContext,
				TPMS_NV_PUBLIC *nvPublic,
				TPMI_RH_NV_INDEX handle);
#endif
static TPM_RC TSS_NVPublic_Delete(TSS_CONTEXT *tssContext,
				  TPMI_RH_NV_INDEX nvIndex);
#ifdef TPM_TSS_NOFILE
static TPM_RC TSS_NvPublic_GetSlotForHandle(TSS_CONTEXT *tssContext,
					    size_t *slotIndex,
					    TPMI_RH_NV_INDEX nvIndex);
#endif

static TPM_RC TSS_Command_Decrypt(TSS_AUTH_CONTEXT *tssAuthContext,
				  struct TSS_HMAC_CONTEXT *session[],
				  TPMI_SH_AUTH_SESSION sessionHandle[],
				  unsigned int sessionAttributes[]);
#ifndef TPM_TSS_NOCRYPTO
static TPM_RC TSS_Command_DecryptXor(TSS_AUTH_CONTEXT *tssAuthContext,
				     struct TSS_HMAC_CONTEXT *session);
static TPM_RC TSS_Command_DecryptAes(TSS_AUTH_CONTEXT *tssAuthContext,
				     struct TSS_HMAC_CONTEXT *session);

#endif	/* TPM_TSS_NOCRYPTO */
static TPM_RC TSS_Response_Encrypt(TSS_AUTH_CONTEXT *tssAuthContext,
				   struct TSS_HMAC_CONTEXT *session[],
				   TPMI_SH_AUTH_SESSION sessionHandle[],
				   unsigned int sessionAttributes[]);
#ifndef TPM_TSS_NOCRYPTO
static TPM_RC TSS_Response_EncryptXor(TSS_AUTH_CONTEXT *tssAuthContext,
				      struct TSS_HMAC_CONTEXT *session);
static TPM_RC TSS_Response_EncryptAes(TSS_AUTH_CONTEXT *tssAuthContext,
				      struct TSS_HMAC_CONTEXT *session);

static TPM_RC TSS_Command_ChangeAuthProcessor(TSS_CONTEXT *tssContext,
					      struct TSS_HMAC_CONTEXT *session,
					      size_t handleNumber,
					      COMMAND_PARAMETERS *in);
#endif	/* TPM_TSS_NOCRYPTO */

#ifdef TPM_TSS_NODEPRECATEDALGS
static TPM_RC TSS_Command_CheckParameters(TPM_CC commandCode,
					  COMMAND_PARAMETERS *in);
#endif
static TPM_RC TSS_Command_PreProcessor(TSS_CONTEXT *tssContext,
				       TPM_CC commandCode,
				       COMMAND_PARAMETERS *in,
				       EXTRA_PARAMETERS *extra);
static TPM_RC TSS_Response_PostProcessor(TSS_CONTEXT *tssContext,
					 COMMAND_PARAMETERS *in,
					 RESPONSE_PARAMETERS *out,
					 EXTRA_PARAMETERS *extra);

static TPM_RC TSS_Sessions_GetDecryptSession(unsigned int *isDecrypt,
					     unsigned int *decryptSession,
					     TPMI_SH_AUTH_SESSION sessionHandle[],
					     unsigned int sessionAttributes[]);
static TPM_RC TSS_Sessions_GetEncryptSession(unsigned int *isEncrypt,
					     unsigned int *encryptSession,
					     TPMI_SH_AUTH_SESSION sessionHandle[],
					     unsigned int sessionAttributes[]);

#ifndef TPM_TSS_NOFILE
static TPM_RC TSS_HashToString(char *str, uint8_t *digest);
#endif
#ifndef TPM_TSS_NOCRYPTO
#ifndef TPM_TSS_NORSA
static TPM_RC TSS_RSA_Salt(TPM2B_DIGEST 		*salt,
			   TPM2B_ENCRYPTED_SECRET	*encryptedSalt,
			   TPMT_PUBLIC			*publicArea);
#endif /* TPM_TSS_NORSA */
#endif /* TPM_TSS_NOCRYPTO */
extern int tssVerbose;
extern int tssVverbose;
extern int tssFirstCall;


TPM_RC TSS_Execute20(TSS_CONTEXT *tssContext,
		     RESPONSE_PARAMETERS *out,
		     COMMAND_PARAMETERS *in,
		     EXTRA_PARAMETERS *extra,
		     TPM_CC commandCode,
		     va_list ap)
{
    TPM_RC		rc = 0;
	
#ifdef TPM_TSS_NODEPRECATEDALGS
    if (rc == 0) {
	rc = TSS_Command_CheckParameters(commandCode, in);
    }
#endif

    /* create a TSS authorization context */
    if (rc == 0) {
	TSS_InitAuthContext(tssContext->tssAuthContext);
    }
    /* handle any command specific command pre-processing */
    if (rc == 0) {
	rc = TSS_Command_PreProcessor(tssContext,
				      commandCode,
				      in,
				      extra);
    }
    /* marshal input parameters */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute20: Command %08x marshal\n", commandCode);
	rc = TSS_Marshal(tssContext->tssAuthContext,
			 in,
			 commandCode);
    }
    /* execute the command */
    if (rc == 0) {
	rc = TSS_Execute_valist(tssContext, in, ap);
    }
    /* unmarshal the response parameters */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute20: Command %08x unmarshal\n", commandCode);
	rc = TSS_Unmarshal(tssContext->tssAuthContext, out);
    }
    /* handle any command specific response post-processing */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute20: Command %08x post processor\n", commandCode);
	rc = TSS_Response_PostProcessor(tssContext,
					in,
					out,
					extra);
    }
    return rc;
}

/* TSS_Execute_valist() transmits the marshaled command and receives the marshaled response.

   varargs are TPMI_SH_AUTH_SESSION sessionHandle, const char *password, unsigned int
   sessionAttributes

   Terminates with sessionHandle TPM_RH_NULL

   Processes up to MAX_SESSION_NUM sessions.  It handles HMAC generation and command and response
   parameter encryption.  It loads each session context, rolls nonces, and saves or deletes the
   session context.
*/

static TPM_RC TSS_Execute_valist(TSS_CONTEXT *tssContext,
				 COMMAND_PARAMETERS *in,
				 va_list ap)
{
    TPM_RC		rc = 0;
    int 		done;
    int 		haveNames = FALSE;	/* names are common to all HMAC sessions */
    size_t		i = 0;

    /* the vararg parameters */
    TPMI_SH_AUTH_SESSION sessionHandle[MAX_SESSION_NUM];
    const char 		*password[MAX_SESSION_NUM];
    unsigned int	sessionAttributes[MAX_SESSION_NUM]; 

    /* structures filled in */
    TPMS_AUTH_COMMAND 	*authCommand[MAX_SESSION_NUM];
    TPMS_AUTH_RESPONSE 	*authResponse[MAX_SESSION_NUM];
    
    /* pointer to the above structures as used */
    TPMS_AUTH_COMMAND 	*authC[MAX_SESSION_NUM];
    TPMS_AUTH_RESPONSE 	*authR[MAX_SESSION_NUM];

    /* TSS sessions */
    struct TSS_HMAC_CONTEXT *session[MAX_SESSION_NUM];
    TPM2B_NAME *names[MAX_SESSION_NUM];
	
    
    for (i = 0 ; i < MAX_SESSION_NUM ; i++) {
	authCommand[i] = NULL;		/* for safe free */
	authResponse[i] = NULL;		/* for safe free */
 	names[i] = NULL;		/* for safe free */
	authC[i] = NULL;		/* array of TPMS_AUTH_COMMAND structures, NULL for
					   TSS_SetCmdAuths */
	authR[i] = NULL;		/* array of TPMS_AUTH_RESPONSE structures, NULL for
					   TSS_GetRspAuths */
	session[i] = NULL;		/* for free, used for HMAC and encrypt/decrypt sessions */
	/* the varargs list inputs */
	sessionHandle[i] = TPM_RH_NULL;
	password[i] = NULL;
	sessionAttributes[i] = 0;
    }
    /* Step 1: initialization */
    if (tssVverbose) printf("TSS_Execute_valist: Step 1: initialization\n");
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) ; i++) {
	if (rc == 0) {
	    rc = TSS_Malloc((unsigned char **)&authCommand[i],	/* freed @1 */
			    sizeof(TPMS_AUTH_COMMAND));
	}
	if (rc == 0) {
	    rc = TSS_Malloc((unsigned char **)&authResponse[i],	/* freed @2 */
			    sizeof(TPMS_AUTH_RESPONSE));
	}
	if (rc == 0) {
	    rc = TSS_Malloc((unsigned char **)&names[i],	/* freed @3 */
			    sizeof(TPM2B_NAME));
	}
	if (rc == 0) {
	    names[i]->b.size = 0;	/* to ignore unused names in cpHash calculation */
	}
    }
    /* Step 2: gather the command authorizations

       Process PWAP immediately
       For HMAC, get the session context
    */
    done = FALSE;
    for (i = 0 ; (rc == 0) && !done && (i < MAX_SESSION_NUM) ; i++) {
 	sessionHandle[i] = va_arg(ap, TPMI_SH_AUTH_SESSION);	/* first vararg is the session
								   handle */
	password[i]= va_arg(ap, const char *);			/* second vararg is the password */
	sessionAttributes[i] = va_arg(ap, unsigned int);	/* third argument is
								   sessionAttributes */
	sessionAttributes[i] &= 0xff;				/* is uint8_t */

	if (sessionHandle[i] != TPM_RH_NULL) {			/* varargs termination value */ 

	    if (tssVverbose) printf("TSS_Execute_valist: Step 2: authorization %u\n",
				    (unsigned int)i);
	    if (tssVverbose) printf("TSS_Execute_valist: session %u handle %08x\n",
				    (unsigned int)i, sessionHandle[i]);
	    /* make used, non-NULL for command and response varargs */
	    authC[i] = authCommand[i];
	    authR[i] = authResponse[i];

	    /* if password session, populate authC with password, etc. immediately */
	    if (sessionHandle[i] == TPM_RS_PW) {
		rc = TSS_PwapSession_Set(authC[i], password[i]);
	    }
	    /* if HMAC or encrypt/decrypt session  */
	    else {
		/* initialize a TSS HMAC session */
		if (rc == 0) {
		    rc = TSS_HmacSession_GetContext(&session[i]);
		}
		/* load the session created by startauthsession */
		if (rc == 0) {
		    rc = TSS_HmacSession_LoadSession(tssContext, session[i], sessionHandle[i]);
		}
		/* if there is at least one HMAC session, get the names corresponding to the
		   handles */
		if ((session[i]->sessionType == TPM_SE_HMAC) ||		/* HMAC session. OR */
		    ((session[i]->sessionType == TPM_SE_POLICY) &&	/* Policy session AND */

#ifndef TPM_TSS_NOCRYPTO
		     ((session[i]->isAuthValueNeeded) || 		/* PolicyAuthValue ran, OR */
		      (session[i]->sessionKey.b.size != 0)))		/* Already session key (bind or salt) */
#else
		    (session[i]->isAuthValueNeeded))		/* PolicyAuthValue ran, OR */
#endif	/* TPM_TSS_NOCRYPTO */
		    ) {	
		    if ((rc == 0) && !haveNames) {
			rc = TSS_Name_GetAllNames(tssContext, names);
			haveNames = TRUE;	/* get only once, minor optimization */
		    }
		}
	    }
	}
	else {
	    done = TRUE;
	}
    }
    /* Step 3: Roll nonceCaller, save in the session context for the response */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (sessionHandle[i] != TPM_RS_PW) {		/* no nonce for password sessions */
	    if (tssVverbose)
		printf("TSS_Execute_valist: Step 3: nonceCaller %08x\n", sessionHandle[i]);
#ifndef TPM_TSS_NOCRYPTO
	    rc = TSS_HmacSession_SetNonceCaller(session[i], authC[i]);
#else
	    authC[i]->nonce.b.size = 16;
	    memset(&authC[i]->nonce.b.buffer, 0, 16);
#endif	/* TPM_TSS_NOCRYPTO */
	}
	if (tssVverbose) {
	    TPMA_SESSION attributes;
	    attributes.val = (uint8_t)sessionAttributes[i];	/* upper bytes already masked */
	    TSS_TPM_HANDLE_Print("sessionHandle", sessionHandle[i], 8);	
	    TSS_TPMA_SESSION_Print(attributes, 8);
	}
    }

#ifndef TPM_TSS_NOCRYPTO
    /* Step 4: Calculate the HMAC key */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (sessionHandle[i] != TPM_RS_PW) {		/* no HMAC key for password sessions */
	    if (tssVverbose) printf("TSS_Execute_valist: Step 4: Session %u HMAC key for %08x\n",
				    (unsigned int)i, sessionHandle[i]);
	    rc = TSS_HmacSession_SetHmacKey(tssContext, session[i], i, password[i]);
	}
    }
#endif	/* TPM_TSS_NOCRYPTO */
    /* Step 5: command parameter encryption */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 5: command encrypt\n");
	rc = TSS_Command_Decrypt(tssContext->tssAuthContext,
				 session,
				 sessionHandle,
				 sessionAttributes);
    }
    /* Step 6: for each HMAC session, calculate cpHash, calculate the HMAC, and set it in
       TPMS_AUTH_COMMAND */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 6 calculate HMACs\n");
	rc = TSS_HmacSession_SetHMAC(tssContext->tssAuthContext,	/* TSS auth context */
				     session,		/* TSS session contexts */
				     authC,		/* output: command authorizations */
				     sessionHandle,	/* list of session handles for the command */
				     sessionAttributes, /* attributes for this command */
				     password,		/* for plaintext password sessions */
				     names[0],		/* Name */
				     names[1],		/* Name */
				     names[2]);		/* Name */
    }
    /* Step 7: set the command authorizations in the TSS command stream */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 7 set command authorizations\n");
	rc = TSS_SetCmdAuths(tssContext->tssAuthContext,
			     authC[0],
			     authC[1],
			     authC[2],
			     NULL);
    }
    /* Step 8: process the command.  Normally returns the TPM response code. */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 8: process the command\n");
	rc = TSS_AuthExecute(tssContext);
    }
    /* Step 9: get the response authorizations from the TSS response stream */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 9 get response authorizations\n");
	rc = TSS_GetRspAuths(tssContext->tssAuthContext,
			     authR[0],
			     authR[1],
			     authR[2],
			     NULL);
    }
    /* Step 10: process the response authorizations, validate the HMAC */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (tssVverbose)
	    printf("TSS_Execute_valist: Step 10: process response authorization %08x\n",
		   sessionHandle[i]);
	if (sessionHandle[i] == TPM_RS_PW) {
	    rc = TSS_PwapSession_Verify(authR[i]);
	}
	/* HMAC session */
	else {
#ifndef TPM_TSS_NOCRYPTO
	    /* save nonceTPM in the session context */
	    if (rc == 0) {
		rc = TSS_TPM2B_Copy(&session[i]->nonceTPM.b, &authR[i]->nonce.b, sizeof(TPMU_HA));
	    }
#endif	/* TPM_TSS_NOCRYPTO */
	    /* the HMAC key is already part of the TSS session context.  For policy sessions with
	       policy password, the response hmac is empty. */
	    if ((session[i]->sessionType == TPM_SE_HMAC) ||
		((session[i]->sessionType == TPM_SE_POLICY) && (session[i]->isAuthValueNeeded))) {
#ifndef TPM_TSS_NOCRYPTO
		if (rc == 0) {
		    rc = TSS_Command_ChangeAuthProcessor(tssContext, session[i], i, in);
		}
		if (rc == 0) {
		    rc = TSS_HmacSession_Verify(tssContext->tssAuthContext, /* authorization
									       context */
						session[i],	/* TSS session context */
						authR[i]);	/* input: response authorization */
		}
#else
		in = in;
		if (tssVerbose)
		    printf("TSS_Execute_valist: "
			   "Error, HMAC verify with no crypto not implemented\n");
		rc = TSS_RC_NOT_IMPLEMENTED;
#endif	/* TPM_TSS_NOCRYPTO */
	    }
	}
    }
    /* Step 11: process the audit flag */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if ((sessionHandle[i] != TPM_RS_PW) &&
	    (session[i]->bind != TPM_RH_NULL) &&
	    (authR[i]->sessionAttributes.val & TPMA_SESSION_AUDIT)) {
	    if (tssVverbose) printf("TSS_Execute_valist: Step 11: process bind audit flag %08x\n",
				    sessionHandle[i]);
	    /* if bind audit session, bind value is lost and further use requires authValue */
	    session[i]->bind = TPM_RH_NULL;
	}
    }
    /* Step 12: process the response continue flag */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (sessionHandle[i] != TPM_RS_PW) {
	    if (tssVverbose) {
		TSS_TPMS_AUTH_RESPONSE_Print(authR[i], 8);

	    }
	    if (tssVverbose) printf("TSS_Execute_valist: Step 12: process continue flag %08x\n",
				    sessionHandle[i]);
	    rc = TSS_HmacSession_Continue(tssContext, session[i], authR[i]);
	}
    }
    /* Step 13: response parameter decryption */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Execute_valist: Step 13: response decryption\n");
	rc = TSS_Response_Encrypt(tssContext->tssAuthContext,
				  session,
				  sessionHandle,
				  sessionAttributes);
    }
    /* cleanup */
    for (i = 0 ; i < MAX_SESSION_NUM ; i++) {
	TSS_HmacSession_FreeContext(session[i]);
	free(authCommand[i]);		/* @1 */
 	free(authResponse[i]);		/* @2 */
	free(names[i]);			/* @3 */
    }
    return rc;
}

/*
  PWAP - Password Session
*/

/* TSS_PwapSession_Set() sets all members of the TPMS_AUTH_COMMAND structure for a PWAP session.
 */

static TPM_RC TSS_PwapSession_Set(TPMS_AUTH_COMMAND *authCommand,
				  const char *password)
{
    TPM_RC		rc = 0;
    
    if (rc == 0) {
	authCommand->sessionHandle = TPM_RS_PW;
	authCommand->nonce.t.size = 0;
	authCommand->sessionAttributes.val = 0;
    }
    if (password != NULL) {
	rc = TSS_TPM2B_StringCopy(&authCommand->hmac.b,
				  password, sizeof(authCommand->hmac.t.buffer));
    }
    else {
	authCommand->hmac.t.size = 0;
    }
    return rc;
}

/* TSS_PwapSession_Verify() verifies the PWAP session response. */

static TPM_RC TSS_PwapSession_Verify(TPMS_AUTH_RESPONSE *authResponse)
{
    TPM_RC		rc = 0;

    if (rc == 0) {
	if (authResponse->nonce.t.size != 0) {
	    if (tssVerbose) printf("TSS_PwapSession_Verify: nonce size %u not zero\n",
				   authResponse->nonce.t.size);
	    rc = TSS_RC_BAD_PWAP_NONCE;
	}
    }
    if (rc == 0) {
	if (authResponse->sessionAttributes.val != TPMA_SESSION_CONTINUESESSION) {
	    if (tssVerbose) printf("TSS_PwapSession_Verify: continue %02x not set\n",
				   authResponse->sessionAttributes.val);
	    rc = TSS_RC_BAD_PWAP_ATTRIBUTES;
	}
    }
    if (rc == 0) {
	if (authResponse->hmac.t.size != 0) {
	    if (tssVerbose) printf("TSS_PwapSession_Verify: HMAC size %u not zero\n",
				   authResponse->hmac.t.size);
	    rc = TSS_RC_BAD_PWAP_HMAC;
	}
    }
    return rc;
}

/*
  HMAC Session
*/

static TPM_RC TSS_HmacSession_GetContext(struct TSS_HMAC_CONTEXT **session)
{
    TPM_RC rc = 0;

    if (rc == 0) {
        rc = TSS_Malloc((uint8_t **)session, sizeof(TSS_HMAC_CONTEXT));
    }
    if (rc == 0) {
	TSS_HmacSession_InitContext(*session);
    }
    return rc;
}

static void TSS_HmacSession_InitContext(struct TSS_HMAC_CONTEXT *session)
{
    session->sessionHandle = TPM_RH_NULL;
    session->authHashAlg = TPM_ALG_NULL;
#ifndef TPM_TSS_NOCRYPTO
    session->sizeInBytes = 0;
#endif
    session->symmetric.algorithm = TPM_ALG_NULL;
    session->bind = TPM_RH_NULL;
    session->bindName.b.size = 0;
    session->bindAuthValue.t.size = 0;
#ifndef TPM_TSS_NOCRYPTO
    memset(session->nonceTPM.t.buffer, 0, sizeof(TPMU_HA));
    session->nonceTPM.b.size = 0;
    memset(session->nonceCaller.t.buffer, 0, sizeof(TPMU_HA));
    session->nonceCaller.b.size = 0;
    memset(session->sessionKey.t.buffer, 0, sizeof(TPMU_HA));
    session->sessionKey.b.size = 0;
#endif
    session->sessionType = 0;
    session->isPasswordNeeded = FALSE;
    session->isAuthValueNeeded = FALSE;
    memset(session->hmacKey.t.buffer, 0, sizeof(TPMU_HA) + sizeof(TPMU_HA));
    session->hmacKey.b.size = 0;
#ifndef TPM_TSS_NOCRYPTO
    memset(session->sessionValue.t.buffer, 0, sizeof(TPMU_HA) + sizeof(TPMU_HA));
    session->sessionValue.b.size = 0;
#endif
}

void TSS_HmacSession_FreeContext(struct TSS_HMAC_CONTEXT *session)
{
    if (session != NULL) {
	TSS_HmacSession_InitContext(session);
	free(session);
    }
    return;
}

/* TSS_HmacSession_SetSessionKey() is called by the StartAuthSession post processor to calculate and
   store the session key

   19.6.8	sessionKey Creation
*/

#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_HmacSession_SetSessionKey(TSS_CONTEXT *tssContext,
					    struct TSS_HMAC_CONTEXT *session,
					    TPM2B_DIGEST *salt,
					    TPMI_DH_ENTITY bind,
					    TPM2B_AUTH *bindAuthValue)
{
    TPM_RC		rc = 0;
    TPM2B_KEY 		key;		/* HMAC key for the KDFa */

    if (rc == 0) {
	/* save the bind handle, non-null indicates a bound session */
	session->bind = bind;
	/* if bind, save the bind Name in the session context.  The handle might change, but the
	   name will not */
	if ((rc == 0) && (bind != TPM_RH_NULL)) {
	    rc = TSS_Name_GetName(tssContext, &session->bindName, bind);
	}
    }
    if (rc == 0) {
        if ((bind != TPM_RH_NULL) ||
	    (salt->b.size != 0)) {

	    /* session key is bindAuthValue || salt */
	    /* copy bindAuthValue.  This is set during the post processor to either the supplied
	       bind password or Empty */
	    if (rc == 0) {
		rc = TSS_TPM2B_Copy(&key.b, &bindAuthValue->b, sizeof(TPMU_HA) + sizeof(TPMT_HA));
	    }
	    /* copy salt.  This is set during the postprocessor to either the salt from the
	       preprocessor or empty. */
	    if (rc == 0) {
		rc = TSS_TPM2B_Append(&key.b, &salt->b, sizeof(TPMU_HA) + sizeof(TPMT_HA));
	    }
	    if (rc == 0) {
		if (tssVverbose) TSS_PrintAll("TSS_HmacSession_SetSessionKey: KDFa HMAC key",
					      key.b.buffer, key.b.size);
	    }
	    /* KDFa for the session key */
	    if (rc == 0) {
		rc = TSS_KDFA(session->sessionKey.b.buffer,
			      session->authHashAlg,
			      &key.b,
			      "ATH",
			      &session->nonceTPM.b,
			      &session->nonceCaller.b,
			      session->sizeInBytes * 8);
	    }
	    if (rc == 0) {
		session->sessionKey.b.size = session->sizeInBytes;
		if (tssVverbose)
		    TSS_PrintAll("TSS_HmacSession_SetSessionKey: Session key",
				 session->sessionKey.b.buffer, session->sessionKey.b.size);
	    }
	}
	else {
	    session->sessionKey.b.size = 0;
	}
    }
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

/* TSS_HmacSession_SaveSession() saves a session in two cases:

   The initial session from startauthsession
   The updated session a TPM response
*/


static TPM_RC TSS_HmacSession_SaveSession(TSS_CONTEXT *tssContext,
					  struct TSS_HMAC_CONTEXT *session)
{
    TPM_RC	rc = 0;
    uint8_t 	*buffer = NULL;		/* marshaled TSS_HMAC_CONTEXT */
    uint16_t	written = 0;
#ifndef TPM_TSS_NOFILE
    char	sessionFilename[TPM_DATA_DIR_PATH_LENGTH];
    uint8_t *outBuffer = NULL;
    uint32_t outLength;
#endif
    
    if (tssVverbose) printf("TSS_HmacSession_SaveSession: handle %08x\n", session->sessionHandle);
    if (rc == 0) {
	rc = TSS_Structure_Marshal(&buffer,	/* freed @1 */
				   &written,
				   session,
				   (MarshalFunction_t)TSS_HmacSession_Marshal);
    }
#ifndef TPM_TSS_NOFILE
    if (rc == 0) {
#ifndef TPM_TSS_NOCRYPTO
	/* if the flag is set, encrypt the session state before store */
	if (tssContext->tssEncryptSessions) {
	    rc = TSS_AES_Encrypt(tssContext->tssSessionEncKey,
				 &outBuffer,   	/* output, freed @2 */
				 &outLength,	/* output */
				 buffer,	/* input */
				 written);	/* input */
	}
	/* else store the session state in plaintext */
	else {
#endif	/* TPM_TSS_NOCRYPTO */
	    outBuffer = buffer;
	    outLength = written;
#ifndef TPM_TSS_NOCRYPTO
	}
#endif	/* TPM_TSS_NOCRYPTO */
    }
    /* save the session in a hard coded file name hxxxxxxxx.bin where xxxxxxxx is the session
       handle */
    if (rc == 0) {
	sprintf(sessionFilename, "%s/h%08x.bin",
		tssContext->tssDataDirectory, session->sessionHandle);
    }
    if (rc == 0) {
	rc = TSS_File_WriteBinaryFile(outBuffer,
				      outLength,
				      sessionFilename);
    }
    if (tssContext->tssEncryptSessions) {
	free(outBuffer);	/* @2 */
    }
#else		/* no file support, save to context */
    if (rc == 0) {
	rc = TSS_HmacSession_SaveData(tssContext,
				      session->sessionHandle,
				      written, buffer);
    }
#endif
    free(buffer);	/* @1 */
    return rc;
}

/* TSS_HmacSession_LoadSession() loads an existing HMAC session context saved by:

   startauthsession
   an update after a TPM response
*/

static TPM_RC TSS_HmacSession_LoadSession(TSS_CONTEXT *tssContext,
					  struct TSS_HMAC_CONTEXT *session,
					  TPMI_SH_AUTH_SESSION	sessionHandle)
{
    TPM_RC		rc = 0;
    uint8_t 		*buffer = NULL;
    uint8_t 		*buffer1 = NULL;
#ifndef TPM_TSS_NOFILE
    size_t 		length = 0;
    char		sessionFilename[TPM_DATA_DIR_PATH_LENGTH];
#endif    
    unsigned char 	*inData = NULL;		/* output */
    uint32_t 		inLength;		/* output */

    if (tssVverbose) printf("TSS_HmacSession_LoadSession: handle %08x\n", sessionHandle);
#ifndef TPM_TSS_NOFILE
    /* load the session from a hard coded file name hxxxxxxxx.bin where xxxxxxxx is the session
       handle */
    if (rc == 0) {
	sprintf(sessionFilename, "%s/h%08x.bin", tssContext->tssDataDirectory, sessionHandle);
	rc = TSS_File_ReadBinaryFile(&buffer,     /* freed @1 */
				     &length,
				     sessionFilename);
    }
    if (rc == 0) {
#ifndef TPM_TSS_NOCRYPTO
	/* if the flag is set, decrypt the session state before unmarshal */
	if (tssContext->tssEncryptSessions) {
	    rc = TSS_AES_Decrypt(tssContext->tssSessionDecKey,
				 &inData,   		/* output, freed @2 */
				 &inLength,		/* output */
				 buffer,		/* input */
				 (uint32_t)length);	/* input */
	}
	/* else the session was loaded in plaintext */
	else {
#endif	/* TPM_TSS_NOCRYPTO */
	    inData = buffer;
	    inLength = (uint32_t)length;
#ifndef TPM_TSS_NOCRYPTO
	}
#endif	/* TPM_TSS_NOCRYPTO */
    }
#else		/* no file support, load from context */
    if (rc == 0) {
	rc = TSS_HmacSession_LoadData(tssContext,
				      &inLength, &inData,
				      sessionHandle);
    }
#endif
    if (rc == 0) {
	uint32_t ilength = inLength;
	buffer1 = inData;
	rc = TSS_HmacSession_Unmarshal(session, &buffer1, &ilength);
    }
#ifndef TPM_TSS_NOFILE
    if (tssContext->tssEncryptSessions) {
	free(inData);	/* @2 */
    }
#endif
    free(buffer);	/* @1 */
    return rc;
}

#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_HmacSession_SaveData(TSS_CONTEXT *tssContext,
				       TPMI_SH_AUTH_SESSION sessionHandle,
				       uint32_t outLength,
				       uint8_t *outBuffer)
{
    TPM_RC	rc = 0;
    size_t	slotIndex;

    /* if this handle is already used, overwrite the slot */
    if (rc == 0) {
	rc = TSS_HmacSession_GetSlotForHandle(tssContext, &slotIndex, sessionHandle);
	if (rc != 0) {
	    rc = TSS_HmacSession_GetSlotForHandle(tssContext, &slotIndex, TPM_RH_NULL);
	    if (rc == 0) {
		tssContext->sessions[slotIndex].sessionHandle = sessionHandle;
	    }
	    else {
		if (tssVerbose)
		    printf("TSS_HmacSession_SaveData: Error, no slot available for handle %08x\n",
			   sessionHandle);
	    }
	}
    }
    /* reallocate memory and adjust the size */
    if (rc == 0) {
	rc = TSS_Realloc(&tssContext->sessions[slotIndex].sessionData, outLength);
    }
    if (rc == 0) {
	tssContext->sessions[slotIndex].sessionDataLength = outLength;
	memcpy(tssContext->sessions[slotIndex].sessionData, outBuffer, outLength);
    }
    return rc;
}

static TPM_RC TSS_HmacSession_LoadData(TSS_CONTEXT *tssContext,
				       uint32_t *inLength, uint8_t **inData,
				       TPMI_SH_AUTH_SESSION sessionHandle)
{
    TPM_RC	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	rc = TSS_HmacSession_GetSlotForHandle(tssContext, &slotIndex, sessionHandle);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_HmacSession_LoadData: Error, no slot found for handle %08x\n",
		       sessionHandle);
	}
    }
    if (rc == 0) {
	*inLength = tssContext->sessions[slotIndex].sessionDataLength;
	*inData = tssContext->sessions[slotIndex].sessionData;
    }
    return rc;
}

static TPM_RC TSS_HmacSession_DeleteData(TSS_CONTEXT *tssContext,
					 TPMI_SH_AUTH_SESSION sessionHandle)
{
    TPM_RC	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	rc = TSS_HmacSession_GetSlotForHandle(tssContext, &slotIndex, sessionHandle);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_HmacSession_DeleteData: Error, no slot found for handle %08x\n",
		       sessionHandle);
	}
    }    
    if (rc == 0) {
	tssContext->sessions[slotIndex].sessionHandle = TPM_RH_NULL;
	/* erase any secrets */
	memset(tssContext->sessions[slotIndex].sessionData, 0,
	       tssContext->sessions[slotIndex].sessionDataLength);
	free(tssContext->sessions[slotIndex].sessionData);
	tssContext->sessions[slotIndex].sessionData = NULL;
	tssContext->sessions[slotIndex].sessionDataLength = 0;
    }
    return rc;
}

/* TSS_HmacSession_GetSlotForHandle() finds the session slot corresponding to the session handle.

   Returns non-zero if no slot is found.
*/

static TPM_RC TSS_HmacSession_GetSlotForHandle(TSS_CONTEXT *tssContext,
					       size_t *slotIndex,
					       TPMI_SH_AUTH_SESSION sessionHandle)
{
    size_t 	i;

    /* search all slots for handle */
    for (i = 0 ; i < (sizeof(tssContext->sessions) / sizeof(TSS_SESSIONS)) ; i++) {
	if (tssContext->sessions[i].sessionHandle == sessionHandle) {
	    *slotIndex = i;
	    return 0;
	}
    }
    return TSS_RC_NO_SESSION_SLOT;
}

#endif

static TPM_RC TSS_HmacSession_Marshal(struct TSS_HMAC_CONTEXT *source,
					uint16_t *written,
					uint8_t **buffer,
					uint32_t *size)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_TPMI_SH_AUTH_SESSION_Marshalu(&source->sessionHandle, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPMI_ALG_HASH_Marshalu(&source->authHashAlg, written, buffer, size);
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_UINT32_Marshalu(&source->sizeInBytes, written, buffer, size);
    }
#endif
    if (rc == 0) {
	rc = TSS_TPMT_SYM_DEF_Marshalu(&source->symmetric, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPMI_DH_ENTITY_Marshalu(&source->bind, written, buffer, size);
    }   
    if (rc == 0) {
	rc = TSS_TPM2B_NAME_Marshalu(&source->bindName, written, buffer, size);
    }
#ifdef TPM_WINDOWS
    /* FIXME Why does a VS release build need a printf here? */
    if (tssVverbose) printf("");
#endif
    if (rc == 0) {
	rc = TSS_TPM2B_AUTH_Marshalu(&source->bindAuthValue, written, buffer, size);
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_TPM2B_NONCE_Marshalu(&source->nonceTPM, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_NONCE_Marshalu(&source->nonceCaller, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_DIGEST_Marshalu(&source->sessionKey, written, buffer, size);
    }
#endif
    if (rc == 0) {
	rc = TSS_TPM_SE_Marshalu(&source->sessionType, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_UINT8_Marshalu(&source->isPasswordNeeded, written, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_UINT8_Marshalu(&source->isAuthValueNeeded, written, buffer, size);
    }  
    return rc;
}

static TPM_RC TSS_HmacSession_Unmarshal(struct TSS_HMAC_CONTEXT *target,
					uint8_t **buffer, uint32_t *size)
{
    TPM_RC rc = 0;

    if (rc == 0) {
	rc = TSS_TPMI_SH_AUTH_SESSION_Unmarshalu(&target->sessionHandle, buffer, size, NO);
    }
    if (rc == 0) {
	rc = TSS_TPMI_ALG_HASH_Unmarshalu(&target->authHashAlg, buffer, size, NO);
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_UINT32_Unmarshalu(&target->sizeInBytes, buffer, size);
    }
#endif
    if (rc == 0) {
	rc = TSS_TPMT_SYM_DEF_Unmarshalu(&target->symmetric, buffer, size, YES);
    }
    if (rc == 0) {
	rc = TSS_TPMI_DH_ENTITY_Unmarshalu(&target->bind, buffer, size, YES);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_NAME_Unmarshalu(&target->bindName, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_AUTH_Unmarshalu(&target->bindAuthValue, buffer, size);
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_TPM2B_NONCE_Unmarshalu(&target->nonceTPM, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_NONCE_Unmarshalu(&target->nonceCaller, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_TPM2B_DIGEST_Unmarshalu(&target->sessionKey, buffer, size);
    }
#endif
    if (rc == 0) {
	rc = TSS_TPM_SE_Unmarshalu(&target->sessionType, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_UINT8_Unmarshalu(&target->isPasswordNeeded, buffer, size);
    }
    if (rc == 0) {
	rc = TSS_UINT8_Unmarshalu(&target->isAuthValueNeeded, buffer, size);
    }
    return rc;
}

/*
  Name handling
*/

/* TSS_Name_GetAllNames() files in the names array based on the handles marshaled into the TSS
   context command stream. */

static TPM_RC TSS_Name_GetAllNames(TSS_CONTEXT *tssContext,
				   TPM2B_NAME **names)
{
    TPM_RC	rc = 0;
    size_t	i;
    size_t	commandHandleCount;	/* number of handles in the command stream */
    TPM_HANDLE  commandHandle;

    /* get the number of handles in the command stream */
    if (rc == 0) {
	rc = TSS_GetCommandHandleCount(tssContext->tssAuthContext, &commandHandleCount);
	if (tssVverbose) printf("TSS_Name_GetAllNames: commandHandleCount %u\n",
				(unsigned int)commandHandleCount);
    }
    for (i = 0 ; (rc == 0) && (i < commandHandleCount) ; i++) {
	/* get a handle from the command stream */
	if (rc == 0) {
	    rc = TSS_GetCommandHandle(tssContext->tssAuthContext,
				      &commandHandle,
				      i);
	}
	/* get the Name corresponding to the handle */
	if (rc == 0) {
	    if (tssVverbose) printf("TSS_Name_GetAllNames: commandHandle %u %08x\n",
				    (unsigned int)i, commandHandle);
	    rc = TSS_Name_GetName(tssContext, names[i], commandHandle);
	}
    }
    return rc;
}

/* TSS_Name_GetName() gets the Name associated with the handle */

static TPM_RC TSS_Name_GetName(TSS_CONTEXT *tssContext,
			       TPM2B_NAME *name,
			       TPM_HANDLE  handle)
{
    TPM_RC	rc = 0;
    TPM_HT 	handleType;

    if (tssVverbose) printf("TSS_Name_GetName: Handle %08x\n", handle);
    handleType = (TPM_HT) ((handle & HR_RANGE_MASK) >> HR_SHIFT);

    /* Table 3 - Equations for Computing Entity Names */
    switch (handleType) {
	/* for these, the Name is simply the handle value */
      case TPM_HT_PCR:
      case TPM_HT_HMAC_SESSION:
      case TPM_HT_POLICY_SESSION:
      case TPM_HT_PERMANENT:
	rc = TSS_TPM2B_CreateUint32(&name->b, handle, sizeof(name->t.name));
	break;
	/* for NV, the Names was calculated at NV read public */
      case TPM_HT_NV_INDEX:
	/* for objects, the Name was returned at creation or load */
      case TPM_HT_TRANSIENT:
      case TPM_HT_PERSISTENT:
	rc = TSS_Name_Load(tssContext, name, handle, NULL);
	break;
      default:
	if (tssVerbose) printf("TSS_Name_GetName: not implemented for handle %08x\n", handle);
	rc = TSS_RC_NAME_NOT_IMPLEMENTED;
	break;
    }
    if (rc == 0) {
	if (tssVverbose)
	    TSS_PrintAll("TSS_Name_GetName: ",
			 name->t.name, name->t.size);
    }
    
    return rc;
}

/* TSS_Name_Store() stores the 'name' parameter in a file.

   If handle is not 0, the handle is used as the file name.

   If 'string' is not NULL, the string is used as the file name.
*/

#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_Name_Store(TSS_CONTEXT *tssContext,
			     TPM2B_NAME *name,
			     TPM_HANDLE handle,
			     const char *string)
{
    TPM_RC 	rc = 0;
    char 	nameFilename[TPM_DATA_DIR_PATH_LENGTH];

    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {
		sprintf(nameFilename, "%s/h%08x.bin", tssContext->tssDataDirectory, handle);
	    }
	    else {
		if (tssVerbose) printf("TSS_Name_Store: handle and string are both null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {
		sprintf(nameFilename, "%s/h%s.bin", tssContext->tssDataDirectory, string);
	    }
	    else {
		if (tssVerbose) printf("TSS_Name_Store: handle and string are both not null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Name_Store: File %s\n", nameFilename);
	rc = TSS_File_WriteBinaryFile(name->b.buffer, name->b.size, nameFilename);
    }
    return rc;
}

#endif

/* TSS_Name_Load() loads the 'name' from a file.

   If handle is not 0, the handle is used as the file name.

   If 'string' is not NULL, the string is used as the file name.
*/
   
#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_Name_Load(TSS_CONTEXT *tssContext,
			    TPM2B_NAME *name,
			    TPM_HANDLE handle,
			    const char *string)
{
    TPM_RC 		rc = 0;
    char 		nameFilename[TPM_DATA_DIR_PATH_LENGTH];
		
    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {
		sprintf(nameFilename, "%s/h%08x.bin", tssContext->tssDataDirectory, handle);
	    }
	    else {
		if (tssVerbose) printf("TSS_Name_Load: handle and string are both null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {
		sprintf(nameFilename, "%s/h%s.bin", tssContext->tssDataDirectory, string);
	    }
	    else {
		if (tssVerbose) printf("TSS_Name_Load: handle and string are both not null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Name_Load: File %s\n", nameFilename);
	rc = TSS_File_Read2B(&name->b,
			     sizeof(name->t.name),
			     nameFilename);
    }
    return rc;
}

#endif

/* TSS_Name_Store() stores the 'name' parameter the TSS context.
   
*/

#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_Name_Store(TSS_CONTEXT *tssContext,
			     TPM2B_NAME *name,
			     TPM_HANDLE handle,
			     const char *string)
{
    TPM_RC 	rc = 0;
    TPM_HT 	handleType;
    size_t	slotIndex;

    if (tssVverbose) printf("TSS_Name_Store: Handle %08x\n", handle);
    handleType = (TPM_HT) ((handle & HR_RANGE_MASK) >> HR_SHIFT);

    switch (handleType) {
      case TPM_HT_NV_INDEX:
	/* for NV, the Name was returned at creation */
	rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
	if (rc != 0) {
	    rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, TPM_RH_NULL);
	    if (rc == 0) {
		tssContext->nvPublic[slotIndex].nvIndex = handle;
	    }
	    else {
		if (tssVerbose)
		    printf("TSS_Name_Store: Error, no slot available for handle %08x\n", handle);
	    }
	}
	if (rc == 0) {
	    tssContext->nvPublic[slotIndex].name = *name;
	}
	break;
      case TPM_HT_TRANSIENT:
      case TPM_HT_PERSISTENT:
	if (rc == 0) {
	    if (string == NULL) {
		if (handle != 0) {
		    /* if this handle is already used, overwrite the slot */
		    rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
		    if (rc != 0) {
			rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, TPM_RH_NULL);
			if (rc == 0) {
			    tssContext->objectPublic[slotIndex].objectHandle = handle;
			}
			else {
			    if (tssVerbose)
				printf("TSS_Name_Store: "
				       "Error, no slot available for handle %08x\n",
				       handle);
			}
		    }
		}
		else {
		    if (tssVerbose) printf("TSS_Name_Store: handle and string are both null");
		    rc = TSS_RC_NAME_FILENAME;
		}
	    }
	    else {
		if (handle == 0) {
		    if (tssVerbose) printf("TSS_Name_Store: string unimplemented");
		    rc = TSS_RC_NAME_FILENAME;
		}
		else {
		    if (tssVerbose) printf("TSS_Name_Store: handle and string are both not null");
		    rc = TSS_RC_NAME_FILENAME;
		}
	    }
	}
	if (rc == 0) {
	    tssContext->objectPublic[slotIndex].name = *name;
	}
	break;
      default:
	if (tssVerbose) printf("TSS_Name_Store: handle type %02x unimplemented", handleType);
	rc = TSS_RC_NAME_FILENAME;
    }
    return rc;
}

#endif

/* TSS_Name_Load() loads the 'name' from the TSS context.
   
*/
   
#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_Name_Load(TSS_CONTEXT *tssContext,
			    TPM2B_NAME *name,
			    TPM_HANDLE handle,
			    const char *string)
{
    TPM_RC 	rc = 0;
    TPM_HT 	handleType;
    size_t	slotIndex;

    string = string;
    
    if (tssVverbose) printf("TSS_Name_Load: Handle %08x\n", handle);
    handleType = (TPM_HT) ((handle & HR_RANGE_MASK) >> HR_SHIFT);

    switch (handleType) {
      case TPM_HT_NV_INDEX:
	rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_Name_Load: Error, no slot found for handle %08x\n", handle);
	}
	if (rc == 0) {
	    *name = tssContext->nvPublic[slotIndex].name;
	}
	break;
      case TPM_HT_TRANSIENT:
      case TPM_HT_PERSISTENT:
	rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_Name_Load: Error, no slot found for handle %08x\n", handle);
	}
	if (rc == 0) {
	    *name = tssContext->objectPublic[slotIndex].name;
	}
	break;
      default:
	if (tssVerbose) printf("TSS_Name_Load: handle type %02x unimplemented", handleType);
	rc = TSS_RC_NAME_FILENAME;
	
    }
    return rc;
}

#endif

/* TSS_Name_Copy() copies the name from either inHandle or inString to either outHandle or
   outString */

static TPM_RC TSS_Name_Copy(TSS_CONTEXT *tssContext,
			    TPM_HANDLE outHandle,
			    const char *outString,
			    TPM_HANDLE inHandle,
			    const char *inString)
{
    TPM_RC 		rc = 0;
    TPM2B_NAME 		name;
    
    if (rc == 0) {
	rc = TSS_Name_Load(tssContext, &name, inHandle, inString);
    }
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &name, outHandle, outString);
    }
    return rc;
}

/* TSS_Public_Store() stores the 'public' parameter in a file.

   If handle is not 0, the handle is used as the file name.

   If 'string' is not NULL, the string is used as the file name.
*/

#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_Public_Store(TSS_CONTEXT *tssContext,
			       TPM2B_PUBLIC *public,
			       TPM_HANDLE handle,
			       const char *string)
{
    TPM_RC 	rc = 0;
    char 	publicFilename[TPM_DATA_DIR_PATH_LENGTH];

    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {		/* store by handle */
		sprintf(publicFilename, "%s/hp%08x.bin", tssContext->tssDataDirectory, handle);
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Store: handle and string are both null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {		/* store by string */
		sprintf(publicFilename, "%s/hp%s.bin", tssContext->tssDataDirectory, string);
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Store: handle and string are both not null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Public_Store: File %s\n", publicFilename);
	rc = TSS_File_WriteStructure(public,
				     (MarshalFunction_t)TSS_TPM2B_PUBLIC_Marshalu,
				     publicFilename);
    }
    return rc;
}

#endif

/* TSS_Public_Load() loads the 'public' parameter from a file.

   If handle is not 0, the handle is used as the file name.

   If 'string' is not NULL, the string is used as the file name.
*/
   
#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_Public_Load(TSS_CONTEXT *tssContext,
			      TPM2B_PUBLIC *public,
			      TPM_HANDLE handle,
			      const char *string)
{
    TPM_RC 	rc = 0;
    char 	publicFilename[TPM_DATA_DIR_PATH_LENGTH];
		
    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {
		sprintf(publicFilename, "%s/hp%08x.bin", tssContext->tssDataDirectory, handle);
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Load: handle and string are both null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {
		sprintf(publicFilename, "%s/hp%s.bin", tssContext->tssDataDirectory, string);
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Load: handle and string are both not null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Public_Load: File %s\n", publicFilename);
	rc = TSS_File_ReadStructureFlag(public,
					(UnmarshalFunctionFlag_t)TSS_TPM2B_PUBLIC_Unmarshalu,
					TRUE,			/* NULL permitted */
					publicFilename);
    }
    return rc;
}

#endif 	/* TPM_TSS_NOFILE */

/* TSS_Public_Copy() copies the TPM2B_PUBLIC from either inHandle or inString to either outHandle or
   outString */

static TPM_RC TSS_Public_Copy(TSS_CONTEXT *tssContext,
			      TPM_HANDLE outHandle,
			      const char *outString,
			      TPM_HANDLE inHandle,
			      const char *inString)
{
    TPM_RC 		rc = 0;
    TPM2B_PUBLIC 	public;
    
    if (rc == 0) {
	rc = TSS_Public_Load(tssContext, &public, inHandle, inString);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &public, outHandle, outString);
    }
    return rc;
}

/* TSS_Public_Store() stores the 'public' parameter in the TSS context. 
 */
   
#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_Public_Store(TSS_CONTEXT *tssContext,
			       TPM2B_PUBLIC *public,
			       TPM_HANDLE handle,
			       const char *string)
{
    TPM_RC 	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {
		/* if this handle is already used, overwrite the slot */
		rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
		if (rc != 0) {
		    rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, TPM_RH_NULL);
		    if (rc == 0) {
			tssContext->objectPublic[slotIndex].objectHandle = handle;
		    }
		    else {
			if (tssVerbose)
			    printf("TSS_Public_Store: Error, no slot available for handle %08x\n",
				   handle);
		    }
		}
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Store: handle and string are both null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {
		if (tssVerbose) printf("TSS_Public_Store: string not implemented yet");
		rc = TSS_RC_NAME_FILENAME;
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Store: handle and string are both not null");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	tssContext->objectPublic[slotIndex].objectPublic = *public;
    }
    return rc;
}

#endif

/* TSS_Public_Load() loaded the object public from the TSS context.
   
 */
   
#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_Public_Load(TSS_CONTEXT *tssContext,
			      TPM2B_PUBLIC *public,
			      TPM_HANDLE handle,
			      const char *string)
{
    TPM_RC 	rc = 0;
    size_t	slotIndex;
		
    if (rc == 0) {
	if (string == NULL) {
	    if (handle != 0) {
		rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
		if (rc != 0) {
		    if (tssVerbose)
			printf("TSS_Public_Load: Error, no slot found for handle %08x\n",
			       handle);
		}
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Load: handle and string are both null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
	else {
	    if (handle == 0) {
		if (tssVerbose) printf("TSS_Public_Load: string not implemented yet");
		rc = TSS_RC_NAME_FILENAME;
	    }
	    else {
		if (tssVerbose) printf("TSS_Public_Load: handle and string are both not null\n");
		rc = TSS_RC_NAME_FILENAME;
	    }
	}
    }
    if (rc == 0) {
	*public = tssContext->objectPublic[slotIndex].objectPublic;
    }
    return rc;
}

#endif 	/* TPM_TSS_NOFILE */

#ifdef TPM_TSS_NOFILE

/* TSS_ObjectPublic_GetSlotForHandle() finds the object public slot corresponding to the handle.

   Returns non-zero if no slot is found.
*/

static TPM_RC TSS_ObjectPublic_GetSlotForHandle(TSS_CONTEXT *tssContext,
						size_t *slotIndex,
						TPM_HANDLE handle)
{
    size_t 	i;

    /* search all slots for handle */
    for (i = 0 ; i < (sizeof(tssContext->sessions) / sizeof(TSS_SESSIONS)) ; i++) {
	if (tssContext->objectPublic[i].objectHandle == handle) {
	    *slotIndex = i;
	    return 0;
	}
    }
    return TSS_RC_NO_OBJECTPUBLIC_SLOT;
}	

#endif

#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_ObjectPublic_DeleteData(TSS_CONTEXT *tssContext, TPM_HANDLE handle)
{
    TPM_RC	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	rc = TSS_ObjectPublic_GetSlotForHandle(tssContext, &slotIndex, handle);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_ObjectPublic_DeleteData: Error, no slot found for handle %08x\n",
		       handle);
	}
    }    
    if (rc == 0) {
	tssContext->objectPublic[slotIndex].objectHandle = TPM_RH_NULL;
    }
    return rc;
}

#endif


/* TSS_DeleteHandle() removes retained state stored by the TSS for a handle 
 */

static TPM_RC TSS_DeleteHandle(TSS_CONTEXT *tssContext,
			       TPM_HANDLE handle)
{
    TPM_RC		rc = 0;
    TPM_HT 		handleType;
#ifndef TPM_TSS_NOFILE
    char		filename[TPM_DATA_DIR_PATH_LENGTH];
#endif

    handleType = (TPM_HT) ((handle & HR_RANGE_MASK) >> HR_SHIFT);
#ifndef TPM_TSS_NOFILE
    /* delete the Name */
    if (rc == 0) {
	sprintf(filename, "%s/h%08x.bin", tssContext->tssDataDirectory, handle);
	if (tssVverbose) printf("TSS_DeleteHandle: delete Name file %s\n", filename);
	rc = TSS_File_DeleteFile(filename);
    }
    /* delete the public if it exists */
    if (rc == 0) {
	if ((handleType == TPM_HT_TRANSIENT) ||
	    (handleType == TPM_HT_PERSISTENT)) {
	    sprintf(filename, "%s/hp%08x.bin", tssContext->tssDataDirectory, handle);
	    if (tssVverbose) printf("TSS_DeleteHandle: delete public file %s\n", filename);
	    TSS_File_DeleteFile(filename);
	}
    }
#else
    /* sessions persist in the context and can be deleted */
    if (rc == 0) {
	switch (handleType) {
	  case TPM_HT_NV_INDEX:
	    rc = TSS_RC_NOT_IMPLEMENTED;
	    break;
	  case TPM_HT_HMAC_SESSION:
	  case TPM_HT_POLICY_SESSION:
	    if (tssVverbose) printf("TSS_DeleteHandle: delete session state %08x\n", handle);
	    rc = TSS_HmacSession_DeleteData(tssContext, handle);
	    break;
	  case TPM_HT_TRANSIENT:
	  case TPM_HT_PERSISTENT:
	    rc = TSS_ObjectPublic_DeleteData(tssContext, handle);
	    break;
	}
    }
#endif
    return rc;
}

#ifndef TPM_TSS_NOCRYPTO

/* TSS_ObjectPublic_GetName() calculates the Name from the TPMT_PUBLIC.  The Name provides security,
   because the Name returned from the TPM2_ReadPublic cannot be trusted.
*/

static TPM_RC TSS_ObjectPublic_GetName(TPM2B_NAME *name,
				       TPMT_PUBLIC *tpmtPublic)
{
    TPM_RC 	rc = 0;
    
    uint16_t 	written = 0;
    TPMT_HA	digest;
    uint32_t 	sizeInBytes = 0;
    uint8_t 	*buffer = NULL;

    if (rc == 0) {
	rc = TSS_Malloc(&buffer, MAX_RESPONSE_SIZE);	/* freed @1 */
    }
    /* marshal the TPMT_PUBLIC */
    if (rc == 0) {
	uint32_t 	size = MAX_RESPONSE_SIZE;
	uint8_t 	*buffer1 = buffer;
	rc = TSS_TPMT_PUBLIC_Marshalu(tpmtPublic, &written, &buffer1, &size);
    }
    /* hash the public area */
    if (rc == 0) {
	sizeInBytes = TSS_GetDigestSize(tpmtPublic->nameAlg);
	digest.hashAlg = tpmtPublic->nameAlg;	/* Name digest algorithm */
	/* generate the TPMT_HA */
	rc = TSS_Hash_Generate(&digest,	
			       written, buffer,
			       0, NULL);
    }
    if (rc == 0) {
	TPMI_ALG_HASH nameAlgNbo;
	/* copy the digest */
	memcpy(name->t.name + sizeof(TPMI_ALG_HASH), (uint8_t *)&digest.digest, sizeInBytes);
	/* copy the hash algorithm */
	nameAlgNbo = htons(tpmtPublic->nameAlg);
	memcpy(name->t.name, (uint8_t *)&nameAlgNbo, sizeof(TPMI_ALG_HASH));
	/* set the size */
	name->t.size = sizeInBytes + (uint16_t)sizeof(TPMI_ALG_HASH);
    }
    free(buffer);	/* @1 */
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */


/* TSS_NVPublic_Store() stores the NV public data in a file.

 */

#ifndef TPM_TSS_NOFILE
#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_NVPublic_Store(TSS_CONTEXT *tssContext,
				 TPMS_NV_PUBLIC *nvPublic,
				 TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    char 	nvpFilename[TPM_DATA_DIR_PATH_LENGTH];

    if (rc == 0) {
	sprintf(nvpFilename, "%s/nvp%08x.bin", tssContext->tssDataDirectory, nvIndex);
	rc = TSS_File_WriteStructure(nvPublic,
				     (MarshalFunction_t)TSS_TPMS_NV_PUBLIC_Marshalu,
				     nvpFilename);
    }
    return rc;
}

#endif
#endif

/* TSS_NVPublic_Load() loads the NV public from a file.

 */

#ifndef TPM_TSS_NOFILE
#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_NVPublic_Load(TSS_CONTEXT *tssContext,
				TPMS_NV_PUBLIC *nvPublic,
				TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    char 	nvpFilename[TPM_DATA_DIR_PATH_LENGTH];

    if (rc == 0) {
	sprintf(nvpFilename, "%s/nvp%08x.bin", tssContext->tssDataDirectory, nvIndex);
	rc = TSS_File_ReadStructure(nvPublic,
				    (UnmarshalFunction_t)TSS_TPMS_NV_PUBLIC_Unmarshalu,
				    nvpFilename);
    }
    return rc;
}

#endif
#endif

#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_NVPublic_Delete(TSS_CONTEXT *tssContext,
				  TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    char 	nvpFilename[TPM_DATA_DIR_PATH_LENGTH];
    
    if (rc == 0) {
	sprintf(nvpFilename, "%s/nvp%08x.bin", tssContext->tssDataDirectory, nvIndex);
	rc = TSS_File_DeleteFile(nvpFilename);
    }
    return rc;
}

#endif

#ifdef TPM_TSS_NOFILE
#ifndef TPM_TSS_NOCRYPTO

/* TSS_NVPublic_Store() stores the NV public data in a file.

 */

static TPM_RC TSS_NVPublic_Store(TSS_CONTEXT *tssContext,
				 TPMS_NV_PUBLIC *nvPublic,
				 TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, nvIndex);
	if (rc != 0) {
	    rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, TPM_RH_NULL);
	    if (rc == 0) {
		tssContext->nvPublic[slotIndex].nvIndex = nvIndex;
	    }
	    else {
		if (tssVerbose)
		    printf("TSS_NVPublic_Store: Error, no slot available for handle %08x\n",
			   nvIndex);
	    }
	}
    }
    if (rc == 0) {
	tssContext->nvPublic[slotIndex].nvPublic = *nvPublic;
    }
    return rc;
}

#endif
#endif

#ifdef TPM_TSS_NOFILE
#ifndef TPM_TSS_NOCRYPTO

/* TSS_NVPublic_Load() loads the NV public from a file.

 */

static TPM_RC TSS_NVPublic_Load(TSS_CONTEXT *tssContext,
				TPMS_NV_PUBLIC *nvPublic,
				TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    size_t	slotIndex;

    if (rc == 0) {
	rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, nvIndex);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_NVPublic_Load: Error, no slot found for handle %08x\n",
		       nvIndex);
	}
    }
    if (rc == 0) {
	*nvPublic = tssContext->nvPublic[slotIndex].nvPublic;
    }
    return rc;
}

#endif
#endif

#ifdef TPM_TSS_NOFILE

static TPM_RC TSS_NVPublic_Delete(TSS_CONTEXT *tssContext,
				  TPMI_RH_NV_INDEX nvIndex)
{
    TPM_RC 	rc = 0;
    size_t	slotIndex;
    
    if (rc == 0) {
	rc = TSS_NvPublic_GetSlotForHandle(tssContext, &slotIndex, nvIndex);
	if (rc != 0) {
	    if (tssVerbose)
		printf("TSS_NVPublic_Delete: Error, no slot found for handle %08x\n",
		       nvIndex);
	}
    }
    if (rc == 0) {
	tssContext->nvPublic[slotIndex].nvIndex = TPM_RH_NULL;
    }
    return rc;
}

#endif

#ifdef TPM_TSS_NOFILE

/* TSS_NvPublic_GetSlotForHandle() finds the object public slot corresponding to the handle.

   Returns non-zero if no slot is found.
*/

static TPM_RC TSS_NvPublic_GetSlotForHandle(TSS_CONTEXT *tssContext,
					    size_t *slotIndex,
					    TPMI_RH_NV_INDEX nvIndex)
{
    size_t 	i;

    /* search all slots for handle */
    for (i = 0 ; i < (sizeof(tssContext->nvPublic) / sizeof(TSS_NVPUBLIC)) ; i++) {
	if (tssContext->nvPublic[i].nvIndex == nvIndex) {
	    *slotIndex = i;
	    return 0;
	}
    }
    return TSS_RC_NO_NVPUBLIC_SLOT;
}	

#endif

/* TSS_NVPublic_GetName() calculates the Name from the TPMS_NV_PUBLIC.  The Name provides security,
   because the Name returned from the TPM2_NV_ReadPublic cannot be trusted.
*/

#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_NVPublic_GetName(TPM2B_NAME *name,
				   TPMS_NV_PUBLIC *nvPublic)
{
    TPM_RC 	rc = 0;
    
    uint16_t 	written = 0;
    TPMT_HA	digest;
    uint32_t 	sizeInBytes = 0;
    uint8_t 	*buffer = NULL;

    if (rc == 0) {
	rc = TSS_Malloc(&buffer, MAX_RESPONSE_SIZE);	/* freed @1 */
    }
    /* marshal the TPMS_NV_PUBLIC */
    if (rc == 0) {
	uint32_t 	size = MAX_RESPONSE_SIZE;
	uint8_t 	*buffer1 = buffer;
	rc = TSS_TPMS_NV_PUBLIC_Marshalu(nvPublic, &written, &buffer1, &size);
    }
    /* hash the public area */
    if (rc == 0) {
	sizeInBytes = TSS_GetDigestSize(nvPublic->nameAlg);
	digest.hashAlg = nvPublic->nameAlg;	/* Name digest algorithm */
	/* generate the TPMT_HA */
	rc = TSS_Hash_Generate(&digest,	
			       written, buffer,
			       0, NULL);
    }
    if (rc == 0) {
	TPMI_ALG_HASH nameAlgNbo;
	/* copy the digest */
	memcpy(name->t.name + sizeof(TPMI_ALG_HASH), (uint8_t *)&digest.digest, sizeInBytes);
	/* copy the hash algorithm */
	nameAlgNbo = htons(nvPublic->nameAlg);
	memcpy(name->t.name, (uint8_t *)&nameAlgNbo, sizeof(TPMI_ALG_HASH));
	/* set the size */
	name->t.size = sizeInBytes + (uint16_t)sizeof(TPMI_ALG_HASH);
    }
    free(buffer);	/* @1 */
    return rc;
}

#endif

#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_HmacSession_SetNonceCaller(struct TSS_HMAC_CONTEXT *session,
					     TPMS_AUTH_COMMAND 	*authC)
{
    TPM_RC		rc = 0;

    /* generate a new nonceCaller */
    if (rc == 0) {
	session->nonceCaller.b.size = session->sizeInBytes;
	rc = TSS_RandBytes(session->nonceCaller.t.buffer, session->sizeInBytes);
    }
    /* nonceCaller for the command */
    if (rc == 0) {
	rc = TSS_TPM2B_Copy(&authC->nonce.b, &session->nonceCaller.b, sizeof(TPMU_HA));
    }
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

#ifndef TPM_TSS_NOCRYPTO

/* TSS_HmacSession_SetHmacKey() calculates the session HMAC key.

   handleNumber is index into the session area.  The first sessions, the authorization sessions,
   have a corresponding handle in the command handle.
*/

static TPM_RC TSS_HmacSession_SetHmacKey(TSS_CONTEXT *tssContext,
					 struct TSS_HMAC_CONTEXT *session,
					 size_t handleNumber,	/* index into the handle area */
					 const char *password)
{
    TPM_RC		rc = 0;
    TPM_HANDLE 		commandHandle;		/* from handle area, for bound session */
    TPM2B_NAME		name;
    TPM2B_AUTH 		authValue;
    int 		bindMatch = FALSE;
    int 		done = FALSE;		/* done with authorization sessions */

    /*
      authHMAC = HMAC sessionAlg ((sessionKey || authValue), 
      (pHash || nonceNewer || nonceOlder 
      { || nonceTPMdecrypt } { || nonceTPMencrypt }
      || sessionAttributes))
    */
    /* HMAC key is sessionKey || authValue */
    /* copy the session key to HMAC key */
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_HmacSession_SetHmacKey: sessionKey",
				      session->sessionKey.b.buffer, session->sessionKey.b.size);
	rc = TSS_TPM2B_Copy(&session->hmacKey.b,
			    &session->sessionKey.b, sizeof(TPMU_HA) + sizeof(TPMT_HA));
    }
    /* copy the session key to sessionValue */
    if (rc == 0) {
	rc = TSS_TPM2B_Copy(&session->sessionValue.b,
			    &session->sessionKey.b, sizeof(TPMU_HA) + sizeof(TPMT_HA));
    }
    if (rc == 0) {
	if (tssVverbose)
	    TSS_PrintAll("TSS_HmacSession_SetHmacKey: preliminary sessionValue",
			 session->sessionValue.b.buffer, session->sessionValue.b.size);
    }
    /* This value is an EmptyAuth if the HMAC is being computed to authorize an action on the
       object to which the session is bound.
    */
    /* The first sessions are authorization sessions.  They can have a bind entity.  All others can
       be encrypt or decrypt sessions, but the authValue is not included in the session key.
    */
    if (rc == 0) {
	AUTH_ROLE authRole = TSS_GetAuthRole(tssContext->tssAuthContext, handleNumber);
	if (authRole == AUTH_NONE) {
	    if (tssVverbose) printf("TSS_HmacSession_SetHmacKey: Done, not auth session\n");
	    done = TRUE;	/* not an authorization session, could be audit or
				   encrypt/decrypt */
	}
    }
    /* If not an authorization session, there is no authValue to append to the HMAC key or encrypt
       sessionValue, regardless of the binding.  Below is for auth sessions. */
    if (!done) {
	/* First, if there was a bind handle, check if the name matches.  Else bindMatch remains
	   FALSE. */
	if (session->bind != TPM_RH_NULL) {
	    /* get the handle for this session */
	    if (tssVverbose)
		printf("TSS_HmacSession_SetHmacKey: Processing bind handle %08x\n", session->bind);
	    if (rc == 0) {
		rc = TSS_GetCommandHandle(tssContext->tssAuthContext,
					  &commandHandle,
					  handleNumber);
	    }
	    /* get the Name corresponding to the handle */
	    if (rc == 0) {
		if (tssVverbose)
		    printf("TSS_HmacSession_SetHmacKey: commandHandle %08x bindHandle %08x\n",
			   commandHandle, session->bind);
		rc = TSS_Name_GetName(tssContext, &name, commandHandle);
	    }
	    /* compare the authorized object name to the bind object name */
	    if (rc == 0) {
		bindMatch = TSS_TPM2B_Compare(&name.b, &session->bindName.b);
		if (tssVverbose) printf("TSS_HmacSession_SetHmacKey: bind match %u\n", bindMatch);
	    }
	}
	/* Second, append password to session key for HMAC key if required */

	/* When performing an HMAC for authorization, the HMAC key is normally the concatenation of
	   the entity's authValue to the sessions sessionKey (created at
	   TPM2_StartAuthSession(). However, if the authorization is for the entity to
	   which the session is bound, the authValue is not included in the HMAC key. When
	   a policy requires that an HMAC be computed, it is always concatenated.
	*/
	if ((rc == 0) &&
	    /* append if HMAC session and not bind match */
	    (((session->sessionType == TPM_SE_HMAC) && !bindMatch) ||
	     /* append if policy and policy authvalue */
	     ((session->sessionType == TPM_SE_POLICY) && session->isAuthValueNeeded)) &&
	    (password != NULL)	/* if password is NULL, nothing to append. */

	    ) {
	    
	    if (tssVverbose)
		printf("TSS_HmacSession_SetHmacKey: Appending authValue to HMAC key\n");
	    /* convert the password to an authvalue */
	    if (rc == 0) {
		rc = TSS_TPM2B_StringCopy(&authValue.b, password, sizeof(authValue.t.buffer));
	    }
	    /* append the authvalue to the session key to create the hmac key */
	    if (rc == 0) {
		rc = TSS_TPM2B_Append(&session->hmacKey.b, &authValue.b,
				      sizeof(TPMU_HA) + sizeof(TPMT_HA));
	    }
	}
	/* Third, append password to session key for sessionValue

	   If a session is also being used for authorization, sessionValue (see 21.2 and 21.3) is
	   sessionKey || authValue. The binding of the session is ignored. If the session is not
	   being used for authorization, sessionValue is sessionKey.
	 */
	/* NOTE This step occurs even if there is a bind match. That is, the password is effectively
	   appended twice. */
	if (rc == 0) {
	    /* if not bind, sessionValue is sessionKey || authValue (same as HMAC key) */
	    if (!bindMatch) {
		if (tssVverbose)
		    printf("TSS_HmacSession_SetHmacKey: "
			   "No bind, appending authValue to sessionValue\n");
		/* convert the password to an authvalue */
		if (rc == 0) {
		    rc = TSS_TPM2B_StringCopy(&authValue.b, password, sizeof(authValue.t.buffer));
		}
		if (rc == 0) {
		    rc = TSS_TPM2B_Append(&session->sessionValue.b, &authValue.b,
					  sizeof(TPMU_HA) + sizeof(TPMT_HA));
		}
	    }
	    /* if bind, sessionValue is sessionKey || bindAuthValue */
	    else {
		if (tssVverbose)
		    printf("TSS_HmacSession_SetHmacKey: "
			   "Bind, appending bind authValue to sessionValue\n");
		if (rc == 0) {
		    rc = TSS_TPM2B_Append(&session->sessionValue.b, &session->bindAuthValue.b,
					  sizeof(TPMU_HA) + sizeof(TPMT_HA));
		}
	    }
	    if (rc == 0) {
		if (tssVverbose)
		    TSS_PrintAll("TSS_HmacSession_SetHmacKey: bindAuthValue",
				 session->bindAuthValue.b.buffer, session->bindAuthValue.b.size);
	    }
	}
    }
    if (rc == 0) {
	if (tssVverbose)
	    TSS_PrintAll("TSS_HmacSession_SetHmacKey: hmacKey",
			 session->hmacKey.b.buffer, session->hmacKey.b.size);
	if (tssVverbose)
	    TSS_PrintAll("TSS_HmacSession_SetHmacKey: sessionValue",
			 session->sessionValue.b.buffer, session->sessionValue.b.size);
    }
    return rc;
}
    
#endif	/* TPM_TSS_NOCRYPTO */

/* TSS_HmacSession_SetHMAC() is used for a command.  It sets all the values in one
   TPMS_AUTH_COMMAND, ready for marshaling into the command packet.

   - gets cpBuffer
   - generates cpHash
   - generates the HMAC
   - copies the result into authCommand

   Unused names must have size 0.

   The HMAC key is already in the session structure.
*/

static TPM_RC TSS_HmacSession_SetHMAC(TSS_AUTH_CONTEXT *tssAuthContext,	/* authorization context */
				      struct TSS_HMAC_CONTEXT *session[],
				      TPMS_AUTH_COMMAND *authCommand[],	/* output: command
									   authorization */
				      TPMI_SH_AUTH_SESSION sessionHandle[], /* session handles in
									       command */
				      unsigned int sessionAttributes[],	/* attributes for this
									   command */
				      const char *password[],
				      TPM2B_NAME *name0,		/* up to 3 names */
				      TPM2B_NAME *name1,	/* unused names have length 0 */
				      TPM2B_NAME *name2)
{
    TPM_RC		rc = 0;
    unsigned int	i = 0;
#ifndef TPM_TSS_NOCRYPTO
    TPMT_HA 		cpHash;
    TPMT_HA 		hmac;
    TPM2B_NONCE	nonceTPMDecrypt;
    TPM2B_NONCE	nonceTPMEncrypt;
    cpHash.hashAlg = TPM_ALG_NULL;	/* for cpHash calculation optimization */
#endif	/* TPM_TSS_NOCRYPTO */


    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) && (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	uint8_t sessionAttr8;
	if (tssVverbose) printf("TSS_HmacSession_SetHMAC: Step 6 session %08x\n", sessionHandle[i]);
	/* password sessions were serviced in step 2. */
	if (sessionHandle[i] == TPM_RS_PW) {
	    continue;
	}
	if (tssVverbose) printf("TSS_HmacSession_SetHMAC: sessionType %02x\n",
				session[i]->sessionType);
	if (tssVverbose) printf("TSS_HmacSession_SetHMAC: isPasswordNeeded %02x\n",
				session[i]->isPasswordNeeded);
	if (tssVverbose) printf("TSS_HmacSession_SetHMAC: isAuthValueNeeded %02x\n",
				session[i]->isAuthValueNeeded);
	/* sessionHandle */
	authCommand[i]->sessionHandle = session[i]->sessionHandle;
	/* attributes come from command */
	sessionAttr8 = (uint8_t)sessionAttributes[i];
	authCommand[i]->sessionAttributes.val = sessionAttr8;

	/* policy session with policy password handled below, no hmac.  isPasswordNeeded is never
	   true for an HMAC session, so don't need to test session type here. */
	if (!(session[i]->isPasswordNeeded)) {
	    /* HMAC session */ 
	    if ((session[i]->sessionType == TPM_SE_HMAC) ||
		/* policy session with TPM2_PolicyAuthValue */
		((session[i]->sessionType == TPM_SE_POLICY) && (session[i]->isAuthValueNeeded)) ||
		/* salted session */
		(session[i]->hmacKey.t.size != 0)
		) {
		/* needs HMAC */
#ifndef TPM_TSS_NOCRYPTO
		if (tssVverbose) printf("TSS_HmacSession_SetHMAC: calculate HMAC\n");
		/* calculate cpHash.  Performance optimization: If there is more than one session,
		   and the hash algorithm is the same, use the previously calculated version. */
		if ((rc == 0) && (cpHash.hashAlg != session[i]->authHashAlg)) {
		    uint32_t cpBufferSize;
		    uint8_t *cpBuffer;
		    TPM_CC commandCode;
		    TPM_CC commandCodeNbo;

		    if (rc == 0) {
			rc = TSS_GetCpBuffer(tssAuthContext,
					     &cpBufferSize,
					     &cpBuffer);
		    }
		    if (rc == 0) {
			if (tssVverbose) TSS_PrintAll("TSS_HmacSession_SetHMAC: cpBuffer",
						      cpBuffer, cpBufferSize);
			cpHash.hashAlg = session[i]->authHashAlg;

			/* cpHash = hash(commandCode [ || authName1		*/
			/*                           [ || authName2		*/
			/*                           [ || authName3 ]]]	*/
			/*                           [ || parameters])	*/
			/* A cpHash can contain just a commandCode only if the lone session is */
			/* an audit session. */

			commandCode = TSS_GetCommandCode(tssAuthContext);
			commandCodeNbo = htonl(commandCode);
			rc = TSS_Hash_Generate(&cpHash,		/* largest size of a digest */
					       sizeof(TPM_CC), &commandCodeNbo,
					       name0->b.size, &name0->b.buffer,
					       name1->b.size, &name1->b.buffer,
					       name2->b.size, &name2->b.buffer,
					       cpBufferSize, cpBuffer,
					       0, NULL);
		    }
		}
		if (i == 0) {
		    unsigned int 	isDecrypt = 0;	/* count number of sessions with decrypt
							   set */
		    unsigned int	decryptSession = 0;	/* which one is decrypt */
		    unsigned int 	isEncrypt = 0;	/* count number of sessions with decrypt
							   set */
		    unsigned int	encryptSession = 0;	/* which one is decrypt */
		    nonceTPMDecrypt.t.size = 0;
		    nonceTPMEncrypt.t.size = 0;
		    /* if a different session is being used for parameter decryption, then the
		       nonceTPM for that session is included in the HMAC of the first authorization
		       session */
		    if (rc == 0) {
			rc = TSS_Sessions_GetDecryptSession(&isDecrypt,
							    &decryptSession,
							    sessionHandle,
							    sessionAttributes);
		    }
		    if ((rc == 0) && isDecrypt && (decryptSession != 0)) {
			rc = TSS_TPM2B_Copy(&nonceTPMDecrypt.b,
					    &session[decryptSession]->nonceTPM.b, sizeof(TPMU_HA));
		    }
		    /* if a different session is being used for parameter encryption, then the
		       nonceTPM for that session is included in the HMAC of the first authorization
		       session */
		    if (rc == 0) {
			rc = TSS_Sessions_GetEncryptSession(&isEncrypt,
							    &encryptSession,
							    sessionHandle,
							    sessionAttributes);
		    }
		    /* Don't include the same nonce twice */
		    if ((rc == 0) && isEncrypt && (encryptSession != 0)) {
			if (!isDecrypt || (encryptSession != decryptSession)) {
			    rc = TSS_TPM2B_Copy(&nonceTPMEncrypt.b, 
						&session[encryptSession]->nonceTPM.b,
						sizeof(TPMU_HA));
			}
		    }
		}
		/* for other than the first session, those nonces are not used */
		else {
		    nonceTPMDecrypt.t.size = 0;
		    nonceTPMEncrypt.t.size = 0;
		}
		/* */
		if (rc == 0) {
		    hmac.hashAlg = session[i]->authHashAlg;
		    rc = TSS_HMAC_Generate(&hmac,				/* output hmac */
					   &session[i]->hmacKey,		/* input key */
					   session[i]->sizeInBytes, (uint8_t *)&cpHash.digest,
					   /* new is nonceCaller */
					   session[i]->nonceCaller.b.size,
					   &session[i]->nonceCaller.b.buffer,
					   /* old is previous nonceTPM */
					   session[i]->nonceTPM.b.size,
					   &session[i]->nonceTPM.b.buffer,
					   /* nonceTPMDecrypt */
					   nonceTPMDecrypt.b.size, nonceTPMDecrypt.b.buffer,
					   /* nonceTPMEncrypt */
					   nonceTPMEncrypt.b.size, nonceTPMEncrypt.b.buffer,
					   /* 1 byte, no endian conversion */
					   sizeof(uint8_t), &sessionAttr8,
					   0, NULL);
		    if (tssVverbose) {
			TSS_PrintAll("TSS_HmacSession_SetHMAC: HMAC key",
				     session[i]->hmacKey.t.buffer, session[i]->hmacKey.t.size);
			TSS_PrintAll("TSS_HmacSession_SetHMAC: cpHash",
				     (uint8_t *)&cpHash.digest, session[i]->sizeInBytes);
			TSS_PrintAll("TSS_HmacSession_Set: nonceCaller",
				     session[i]->nonceCaller.b.buffer,
				     session[i]->nonceCaller.b.size);
			TSS_PrintAll("TSS_HmacSession_SetHMAC: nonceTPM",
				     session[i]->nonceTPM.b.buffer, session[i]->nonceTPM.b.size);
			TSS_PrintAll("TSS_HmacSession_SetHMAC: nonceTPMDecrypt",
				     nonceTPMDecrypt.b.buffer, nonceTPMDecrypt.b.size);
			TSS_PrintAll("TSS_HmacSession_SetHMAC: nonceTPMEncrypt",
				     nonceTPMEncrypt.b.buffer, nonceTPMEncrypt.b.size);
			TSS_PrintAll("TSS_HmacSession_SetHMAC: sessionAttributes",
				     &sessionAttr8, sizeof(uint8_t));
			TSS_PrintAll("TSS_HmacSession_SetHMAC: HMAC",
				     (uint8_t *)&hmac.digest, session[i]->sizeInBytes);
		    }
		}
		/* copy HMAC into authCommand TPM2B_AUTH hmac */
		if (rc == 0) {
		    rc = TSS_TPM2B_Create(&authCommand[i]->hmac.b,
					  (uint8_t *)&hmac.digest,
					  session[i]->sizeInBytes,
					  sizeof(authCommand[i]->hmac.t.buffer));
		}
#else
		tssAuthContext = tssAuthContext;
		name0 = name0;
		name1 = name1;
		name2 = name2;
		if (tssVerbose)
		    printf("TSS_HmacSession_SetHMAC: Error, with no crypto not implemented\n");
		rc = TSS_RC_NOT_IMPLEMENTED;
#endif	/* TPM_TSS_NOCRYPTO */
	    }
	    /* not HMAC, not policy requiring password or hmac */
	    else {
		authCommand[i]->hmac.b.size = 0;
	    }
	}
	/* For a policy session that contains TPM2_PolicyPassword(), the password takes precedence
	   and must be present in hmac. */
	else {		/* isPasswordNeeded true */
	    if (tssVverbose) printf("TSS_HmacSession_SetHMAC: use password\n");
	    /* nonce has already been set */
	    rc = TSS_TPM2B_StringCopy(&authCommand[i]->hmac.b,
				      password[i], sizeof(authCommand[i]->hmac.t.buffer));
	}
    }
    return rc;
}


#ifndef TPM_TSS_NOCRYPTO

/* TSS_HmacSession_Verify() is used for a response.  It uses the values in TPMS_AUTH_RESPONSE to
   validate the response HMAC
*/

static TPM_RC TSS_HmacSession_Verify(TSS_AUTH_CONTEXT *tssAuthContext,	/* authorization context */
				     struct TSS_HMAC_CONTEXT *session,	/* TSS session context */
				     TPMS_AUTH_RESPONSE *authResponse)	/* input: response authorization */
{
    TPM_RC		rc = 0;
    uint32_t		rpBufferSize;
    uint8_t 		*rpBuffer;
    TPMT_HA 		rpHash;
    TPMT_HA 		actualHmac;

    /* get the rpBuffer */
    if (rc == 0) {
	rc = TSS_GetRpBuffer(tssAuthContext, &rpBufferSize, &rpBuffer);
	if (tssVverbose) TSS_PrintAll("TSS_HmacSession_Verify: rpBuffer",
				      rpBuffer, rpBufferSize);
    }
    /* calculate rpHash */
    if (rc == 0) {
	TPM_CC commandCode;
	TPM_CC commandCodeNbo;
	rpHash.hashAlg = session->authHashAlg;
	
	commandCode = TSS_GetCommandCode(tssAuthContext);
	commandCodeNbo = htonl(commandCode);
	
	/* rpHash = HsessionAlg (responseCode || commandCode {|| parameters })	 */
	rc = TSS_Hash_Generate(&rpHash,			/* largest size of a digest */
			       sizeof(TPM_RC), &rc,	/* RC is always 0, no need to endian
							   convert */
			       sizeof(TPM_CC), &commandCodeNbo,
			       rpBufferSize, rpBuffer,
			       0, NULL);
    }
    /* construct the actual HMAC as TPMT_HA */
    if (rc == 0) {
	actualHmac.hashAlg = session->authHashAlg;
	if (authResponse->hmac.t.size != session->sizeInBytes) {
	    if (tssVerbose)
		printf("TSS_HmacSession_Verify: HMAC size %u inconsistent with algorithm %u\n",
		       authResponse->hmac.t.size, session->sizeInBytes);
	    rc = TSS_RC_HMAC_SIZE;
	}
    }
    if (rc == 0) {
	memcpy((uint8_t *)&actualHmac.digest, &authResponse->hmac.t.buffer,
	       authResponse->hmac.t.size);
    }
    /* verify the HMAC */
    if (rc == 0) {
	if (tssVverbose) {
	    TSS_PrintAll("TSS_HmacSession_Verify: HMAC key",
			 session->hmacKey.t.buffer, session->hmacKey.t.size);
	    TSS_PrintAll("TSS_HmacSession_Verify: rpHash",
			 (uint8_t *)&rpHash.digest, session->sizeInBytes);
	    TSS_PrintAll("TSS_HmacSession_Verify: nonceTPM",
			 session->nonceTPM.b.buffer, session->nonceTPM.b.size);
	    TSS_PrintAll("TSS_HmacSession_Verify: nonceCaller",
			 session->nonceCaller.b.buffer, session->nonceCaller.b.size);
	    TSS_PrintAll("TSS_HmacSession_Verify: sessionAttributes",
			 &authResponse->sessionAttributes.val, sizeof(uint8_t));
	    TSS_PrintAll("TSS_HmacSession_Verify: response HMAC",
			 (uint8_t *)&authResponse->hmac.t.buffer, session->sizeInBytes);
	}
	rc = TSS_HMAC_Verify(&actualHmac,		/* input response hmac */
			     &session->hmacKey,		/* input HMAC key */
			     session->sizeInBytes,
			     /* rpHash */
			     session->sizeInBytes, (uint8_t *)&rpHash.digest,
			     /* new is nonceTPM */
			     session->nonceTPM.b.size, &session->nonceTPM.b.buffer,
			     /* old is nonceCaller */
			     session->nonceCaller.b.size, &session->nonceCaller.b.buffer,
			     /* 1 byte, no endian conversion */
			     sizeof(uint8_t), &authResponse->sessionAttributes.val,
			     0, NULL);
    }
    return rc;
}

#endif 	/* TPM_TSS_NOCRYPTO */

/* TSS_HmacSession_Continue() handles the response continueSession flag.  It either saves the
   updated session or deletes the session state. */

static TPM_RC TSS_HmacSession_Continue(TSS_CONTEXT *tssContext,
				       struct TSS_HMAC_CONTEXT *session,
				       TPMS_AUTH_RESPONSE *authR)
{
    TPM_RC		rc = 0;

    if (rc == 0) {
	/* if continue set */
	if (authR->sessionAttributes.val & TPMA_SESSION_CONTINUESESSION) {
	    /* clear the policy flags in preparation for the next use */
	    session->isPasswordNeeded = FALSE;
	    session->isAuthValueNeeded = FALSE;
	    /* save the session */
	    rc = TSS_HmacSession_SaveSession(tssContext, session);
	}
	else {		/* continue clear */
	    /* delete the session state */
	    rc = TSS_DeleteHandle(tssContext, session->sessionHandle);
	}
    }
    return rc;
}

/* TSS_Sessions_GetDecryptSession() searches for a command decrypt session.  If found, returns
   isDecrypt TRUE, and the session number in decryptSession.

*/

static TPM_RC TSS_Sessions_GetDecryptSession(unsigned int *isDecrypt,
					     unsigned int *decryptSession,
					     TPMI_SH_AUTH_SESSION sessionHandle[],
					     unsigned int sessionAttributes[])
{
    TPM_RC		rc = 0;
    unsigned int 	i = 0;

    /* count the number of command decrypt sessions */
    *isDecrypt = 0;				/* number of sessions with decrypt set */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) &&
	     (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (sessionHandle[i] != TPM_RS_PW) {	/* no decrypt for password session */
	    if (sessionAttributes[i] & TPMA_SESSION_DECRYPT) {
		(*isDecrypt)++;		/* count number of decrypt sessions */
		*decryptSession = i;	/* record which one it was */
	    }
	}
    }
    /* how many decrypt sessions were found */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Sessions_GetDecryptSession: Found %u decrypt sessions at %u\n",
				*isDecrypt, *decryptSession);
	if (*isDecrypt > 1) {
	    if (tssVerbose)
		printf("TSS_Sessions_GetDecryptSession: Error, found %u decrypt sessions\n",
		       *isDecrypt);
	    rc = TSS_RC_DECRYPT_SESSIONS;
	}
    }
    return rc;
}

/* TSS_Sessions_GetEncryptSession() searches for a response encrypt session.  If found, returns
   isEncrypt TRUE, and the session number in encryptSession.

*/

static TPM_RC TSS_Sessions_GetEncryptSession(unsigned int *isEncrypt,
					     unsigned int *encryptSession,
					     TPMI_SH_AUTH_SESSION sessionHandle[],
					     unsigned int sessionAttributes[])
{
    TPM_RC		rc = 0;
    unsigned int 	i = 0;

    /* count the number of command encrypt sessions */
    *isEncrypt = 0;		/* number of sessions with encrypt set */
    for (i = 0 ; (rc == 0) && (i < MAX_SESSION_NUM) &&
	     (sessionHandle[i] != TPM_RH_NULL) ; i++) {
	if (sessionHandle[i] != TPM_RS_PW) {	/* no encrypt for password session */
	    if (sessionAttributes[i] & TPMA_SESSION_ENCRYPT) {
		(*isEncrypt)++;		/* count number of encrypt sessions */
		*encryptSession = i;	/* record which one it was */
	    }
	}
    }
    /* how many encrypt sessions were found */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Sessions_GetEncryptSession: Found %u encrypt sessions at %u\n",
				*isEncrypt, *encryptSession);
	if (*isEncrypt > 1) {
	    if (tssVerbose)
		printf("TSS_Sessions_GetEncryptSession: Error, found %u encrypt sessions\n",
		       *isEncrypt);
	    rc = TSS_RC_ENCRYPT_SESSIONS;
	}
    }
    return rc;
}

/* TSS_Command_Decrypt() determines whether any sessions are command decrypt sessions.  If so, it
   encrypts the first command parameter.

   It does common error checking, then calls algorithm specific functions.

*/

static TPM_RC TSS_Command_Decrypt(TSS_AUTH_CONTEXT *tssAuthContext,
				  struct TSS_HMAC_CONTEXT *session[],
				  TPMI_SH_AUTH_SESSION sessionHandle[],
				  unsigned int	sessionAttributes[])
{
    TPM_RC		rc = 0;
    unsigned int 	isDecrypt = 0;		/* count number of sessions with decrypt set */
    unsigned int	decryptSession = 0;	/* which session is decrypt */

    /* determine if there is a decrypt session */
    if (rc == 0) {
	rc = TSS_Sessions_GetDecryptSession(&isDecrypt,
					    &decryptSession,
					    sessionHandle,
					    sessionAttributes);
    }
#ifndef TPM_TSS_NOCRYPTO
    {
	COMMAND_INDEX   tpmCommandIndex;	/* index into TPM table */
	TPM_CC 		commandCode;
	int		decryptSize;		/* size of TPM2B size, 2 if there is a TPM2B, 0 if
						   not */
	uint32_t 	paramSize;		/* size of the parameter to encrypt */	
	uint8_t 	*decryptParamBuffer;
	/* can the command parameter be encrypted */
	if ((rc == 0) && isDecrypt) {
	    /* get the commandCode, stored in TSS during marshal */
	    commandCode  = TSS_GetCommandCode(tssAuthContext);
	    /* get the index into the TPM command attributes table */
	    tpmCommandIndex = CommandCodeToCommandIndex(commandCode);
	    /* can this be a decrypt command (this is size of TPM2B size, not size of parameter) */
	    decryptSize = getDecryptSize(tpmCommandIndex);
	    if (decryptSize != 2) {		/* only handle TPM2B */
		printf("TSS_Command_Decrypt: Error, command cannot be encrypted\n");
		rc = TSS_RC_NO_DECRYPT_PARAMETER;
	    }
	}
	/* get the TPM2B parameter to encrypt */
	if ((rc == 0) && isDecrypt) {
	    rc = TSS_GetCommandDecryptParam(tssAuthContext, &paramSize, &decryptParamBuffer);
	}
	/* if the size of the parameter to encrypt is zero, nothing to encrypt */
	if ((rc == 0) && isDecrypt) {
	    if (paramSize == 0) {
		isDecrypt = FALSE;	/* none, done with this function */
	    }
	}
	/* error checking complete, do the encryption */
	if ((rc == 0) && isDecrypt) {
	    switch (session[decryptSession]->symmetric.algorithm) {
	      case TPM_ALG_XOR:
		rc = TSS_Command_DecryptXor(tssAuthContext, session[decryptSession]);
		break;
	      case TPM_ALG_AES:
		rc = TSS_Command_DecryptAes(tssAuthContext, session[decryptSession]);
		break;
	      default:
		if (tssVerbose) printf("TSS_Command_Decrypt: Error, algorithm %04x not implemented\n",
				       session[decryptSession]->symmetric.algorithm);
		rc = TSS_RC_BAD_DECRYPT_ALGORITHM;
		break;
	    }
	}
    }
#else
    tssAuthContext = tssAuthContext;
    session = session;
    if ((rc == 0) && isDecrypt) {
	if (tssVerbose)
	    printf("TSS_Command_Decrypt: Error, with no crypto not implemented\n");
	rc = TSS_RC_NOT_IMPLEMENTED;
    }
#endif
    return rc;
}

#ifndef TPM_TSS_NOCRYPTO

/* NOTE: if AES also works, do in place encryption */

static TPM_RC TSS_Command_DecryptXor(TSS_AUTH_CONTEXT *tssAuthContext,
				     struct TSS_HMAC_CONTEXT *session)
{
    TPM_RC		rc = 0;
    unsigned int	i;
    uint32_t 		paramSize;
    uint8_t 		*decryptParamBuffer;
    uint8_t 		*mask = NULL;
    uint8_t 		*encryptParamBuffer = NULL;

    /* get the TPM2B parameter to encrypt */
    if (rc == 0) {
	rc = TSS_GetCommandDecryptParam(tssAuthContext, &paramSize, &decryptParamBuffer);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptXor: decrypt in",
				      decryptParamBuffer, paramSize);
    }    
    if (rc == 0) {
	rc = TSS_Malloc(&mask, paramSize);
    }
    if (rc == 0) {
	rc = TSS_Malloc(&encryptParamBuffer, paramSize);
    }
    /* generate the XOR pad */
    /* 21.2	XOR Parameter Obfuscation

       XOR(parameter, hashAlg, sessionValue, nonceNewer, nonceOlder)

       parameter	a variable sized buffer containing the parameter to be obfuscated
       hashAlg		the hash algorithm associated with the session
       sessionValue	the session-specific HMAC key
       nonceNewer	for commands, this will be nonceCaller and for responses it will be nonceTPM
       nonceOlder	for commands, this will be nonceTPM and for responses it will be nonceCaller

       11.4.6.3	XOR Obfuscation

       XOR(data, hashAlg, key, contextU, contextV)
       
       mask = KDFa (hashAlg, key, "XOR", contextU, contextV, data.size * 8)
    */
    /* KDFa for the XOR mask */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Command_DecryptXor: hashAlg %04x\n", session->authHashAlg);
	if (tssVverbose) printf("TSS_Command_DecryptXor: sizeInBits %04x\n", paramSize * 8);
	if (tssVverbose)
	    TSS_PrintAll("TSS_Command_DecryptXor: sessionKey",
			 session->sessionKey.b.buffer, session->sessionKey.b.size);
	if (tssVverbose)
	    TSS_PrintAll("TSS_Command_DecryptXor: sessionValue",
			 session->sessionValue.b.buffer, session->sessionValue.b.size);
	rc = TSS_KDFA(mask,
		      session->authHashAlg,
		      &session->sessionValue.b,
		      "XOR",
		      &session->nonceCaller.b,
		      &session->nonceTPM.b,
		      paramSize * 8);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptXor: mask",
				      mask, paramSize);
    }
    /* XOR */
    for (i = 0 ; (rc == 0) && (i < paramSize ) ; i++)  {
	encryptParamBuffer[i] = decryptParamBuffer[i] ^ mask[i];
    }
    if (rc == 0) {
	rc = TSS_SetCommandDecryptParam(tssAuthContext, paramSize, encryptParamBuffer);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptXor: encrypt out",
				      encryptParamBuffer, paramSize);
    }
    free(mask);
    free(encryptParamBuffer);
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

#ifndef TPM_TSS_NOCRYPTO

/* NOTE: if AES also works, do in place encryption */

static TPM_RC TSS_Command_DecryptAes(TSS_AUTH_CONTEXT *tssAuthContext,
				     struct TSS_HMAC_CONTEXT *session)
{
    TPM_RC		rc = 0;
    uint32_t 		paramSize;
    uint8_t 		*decryptParamBuffer;
    uint8_t 		*encryptParamBuffer = NULL;
    TPM2B_IV		iv;
    uint32_t           	kdfaBits;
    uint16_t		keySizeinBytes;
    uint8_t		symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];	/* AES key + IV */
    
    /* get the TPM2B parameter to encrypt */
    if (rc == 0) {
	rc = TSS_GetCommandDecryptParam(tssAuthContext, &paramSize, &decryptParamBuffer);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptAes: decrypt in",
				      decryptParamBuffer, paramSize);
    }    
    if (rc == 0) {
	rc = TSS_Malloc(&encryptParamBuffer, paramSize);	/* free @1 */
    }
    /* generate the encryption key and IV */
    /* 21.3	CFB Mode Parameter Encryption

       KDFa (hashAlg, sessionValue, "CFB", nonceNewer, nonceOlder, bits)	(34)

       hashAlg		the hash algorithm associated with the session
       sessionValue	the session-specific HMAC key
       "CFB"		label to differentiate use of KDFa() (see 4.2)
       nonceNewer	nonceCaller for a command and nonceTPM for a response
       nonceOlder	nonceTPM for a command and nonceCaller for a response
       bits		the number of bits required for the symmetric key plus an IV
    */
    if (rc == 0) {
	iv.t.size = TSS_Sym_GetBlockSize(session->symmetric.algorithm,
					 session->symmetric.keyBits.aes);
	/* generate random values for both the AES key and the IV */
	kdfaBits = session->symmetric.keyBits.aes + (iv.t.size * 8);

	if (tssVverbose) printf("TSS_Command_DecryptAes: hashAlg %04x\n",
				session->authHashAlg);
	if (tssVverbose) printf("TSS_Command_DecryptAes: AES key bits %u\n",
				session->symmetric.keyBits.aes);
	if (tssVverbose) printf("TSS_Command_DecryptAes: kdfaBits %04x\n",
				kdfaBits);
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptAes: session key",
				      session->sessionKey.b.buffer, session->sessionKey.b.size);

	rc = TSS_KDFA(&symParmString[0],
		      session->authHashAlg,
		      &session->sessionValue.b,
		      "CFB",
		      &session->nonceCaller.b,
		      &session->nonceTPM.b,
		      kdfaBits);
    }
    /* copy the latter part of the kdf output to the IV */
    if (rc == 0) {
	keySizeinBytes = session->symmetric.keyBits.aes / 8;
	memcpy(iv.t.buffer, &symParmString[keySizeinBytes], iv.t.size);
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptAes: IV",
				      iv.t.buffer, iv.t.size);
    }
    /* AES CFB encrypt the command */
    if (rc == 0) {
	TPM_RC crc;
	crc = TSS_AES_EncryptCFB(encryptParamBuffer,			/* output */
				 session->symmetric.keyBits.aes,	/* 128 */
				 symParmString,				/* key */
				 iv.t.buffer,				/* IV */
				 paramSize,				/* length */
				 (uint8_t *)decryptParamBuffer);	/* input */
	if (crc != 0) {
	    if (tssVerbose) printf("TSS_Command_DecryptAes: AES encrypt failed\n");
	    rc = TSS_RC_AES_ENCRYPT_FAILURE;
	}
    }		 
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Command_DecryptAes: encrypt out",
				      encryptParamBuffer, paramSize);
    }
    if (rc == 0) {
	rc = TSS_SetCommandDecryptParam(tssAuthContext, paramSize, encryptParamBuffer);
    }
    free(encryptParamBuffer);	/* @1 */
    return rc;
}    

#endif	/* TPM_TSS_NOCRYPTO */

static TPM_RC TSS_Response_Encrypt(TSS_AUTH_CONTEXT *tssAuthContext,
				   struct TSS_HMAC_CONTEXT *session[],
				   TPMI_SH_AUTH_SESSION sessionHandle[],
				   unsigned int sessionAttributes[])
{
    TPM_RC		rc = 0;
    unsigned int 	isEncrypt = 0;		/* count number of sessions with decrypt set */
    unsigned int	encryptSession = 0;	/* which one is decrypt */
    
    /* determine if there is an encrypt session */
    if (rc == 0) {
	rc = TSS_Sessions_GetEncryptSession(&isEncrypt,
					    &encryptSession,
					    sessionHandle,
					    sessionAttributes);
    }
#ifndef TPM_TSS_NOCRYPTO
    {
	COMMAND_INDEX   tpmCommandIndex;	/* index into TPM table */
	TPM_CC 		commandCode;
	int		encryptSize;		/* size of TPM2B size, 2 if there is a TPM2B, 0 if
						   not */
	uint32_t 	paramSize;		/* size of the parameter to decrypt */	
	uint8_t 	*encryptParamBuffer;
	/* can the response parameter be decrypted */
	if ((rc == 0) && isEncrypt) {
	    /* get the commandCode, stored in TSS during marshal */
	    commandCode  = TSS_GetCommandCode(tssAuthContext);
	    /* get the index into the TPM command attributes table */
	    tpmCommandIndex = CommandCodeToCommandIndex(commandCode);
	    /* can this be a decrypt command */
	    encryptSize = getEncryptSize(tpmCommandIndex);
	    if (encryptSize == 0) {
		if (tssVerbose) printf("TSS_Response_Encrypt: "
				       "Error, response cannot be encrypted\n");
		rc = TSS_RC_NO_ENCRYPT_PARAMETER;
	    }
	}
	/* get the TPM2B parameter to decrypt */
	if ((rc == 0) && isEncrypt) {
	    rc = TSS_GetResponseEncryptParam(tssAuthContext, &paramSize, &encryptParamBuffer);
	}
	/* if the size of the parameter to decrypt is zero, nothing to decrypt */
	if ((rc == 0) && isEncrypt) {
	    if (paramSize == 0) {
		isEncrypt = FALSE;	/* none, done with this function */
	    }
	}
	/* error checking complete, do the decryption */
	if ((rc == 0) && isEncrypt) {
	    switch (session[encryptSession]->symmetric.algorithm) {
	      case TPM_ALG_XOR:
		rc = TSS_Response_EncryptXor(tssAuthContext, session[encryptSession]);
		break;
	      case TPM_ALG_AES:
		rc = TSS_Response_EncryptAes(tssAuthContext, session[encryptSession]);
		break;
	      default:
		if (tssVerbose) printf("TSS_Response_Encrypt: "
				       "Error, algorithm %04x not implemented\n",
				       session[encryptSession]->symmetric.algorithm);
		rc = TSS_RC_BAD_ENCRYPT_ALGORITHM;
		break;
	    }
	}
    }
#else
    tssAuthContext = tssAuthContext;
    session = session;
    if ((rc == 0) && isEncrypt) {
	if (tssVerbose)
	    printf("TSS_Response_Encrypt: Error, with no crypto not implemented\n");
	rc = TSS_RC_NOT_IMPLEMENTED;
    }
#endif
    return rc;
}

#ifndef TPM_TSS_NOCRYPTO

/* NOTE: if CFB also works, do in place decryption */

static TPM_RC TSS_Response_EncryptXor(TSS_AUTH_CONTEXT *tssAuthContext,
				      struct TSS_HMAC_CONTEXT *session)
{
    TPM_RC		rc = 0;
    unsigned int	i;
    uint32_t 		paramSize;
    uint8_t 		*encryptParamBuffer;
    uint8_t 		*mask = NULL;
    uint8_t 		*decryptParamBuffer = NULL;

    /* get the TPM2B parameter to decrypt */
    if (rc == 0) {
	rc = TSS_GetResponseEncryptParam(tssAuthContext,
					 &paramSize, &encryptParamBuffer);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptXor: encrypt in",
				      encryptParamBuffer, paramSize);
    }    
    if (rc == 0) {
	rc = TSS_Malloc(&mask, paramSize);			/* freed @1 */
    }
    if (rc == 0) {
	rc = TSS_Malloc(&decryptParamBuffer, paramSize);	/* freed @2 */
    }
    /* generate the XOR pad */
    /* 21.2	XOR Parameter Obfuscation

       XOR(parameter, hashAlg, sessionValue, nonceNewer, nonceOlder)

       parameter	a variable sized buffer containing the parameter to be obfuscated
       hashAlg		the hash algorithm associated with the session
       sessionValue	the session-specific HMAC key
       nonceNewer	for commands, this will be nonceCaller and for responses it will be nonceTPM
       nonceOlder	for commands, this will be nonceTPM and for responses it will be nonceCaller

       
       11.4.6.3	XOR Obfuscation

       XOR(data, hashAlg, key, contextU, contextV)
       
       mask = KDFa (hashAlg, key, "XOR", contextU, contextV, data.size * 8)
    */
    /* KDFa for the XOR mask */
    if (rc == 0) {
	if (tssVverbose) printf("TSS_Response_EncryptXor: hashAlg %04x\n", session->authHashAlg);
	if (tssVverbose) printf("TSS_Response_EncryptXor: sizeInBits %04x\n", paramSize * 8);
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptXor: session key",
				      session->sessionKey.b.buffer, session->sessionKey.b.size);
	rc = TSS_KDFA(mask,
		      session->authHashAlg,
		      &session->sessionValue.b,
		      "XOR",
		      &session->nonceTPM.b,
		      &session->nonceCaller.b,
		      paramSize * 8);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptXor: mask",
				      mask, paramSize);
    }
    /* XOR */
    for (i = 0 ; (rc == 0) && (i < paramSize ) ; i++)  {
	decryptParamBuffer[i] = encryptParamBuffer[i] ^ mask[i];
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptXor: decrypt out",
				      decryptParamBuffer, paramSize);
    }
    if (rc == 0) {
	rc = TSS_SetResponseDecryptParam(tssAuthContext,
					 paramSize, decryptParamBuffer);
    }
    free(mask);			/* @1 */
    free(decryptParamBuffer);	/* @2 */
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

#ifndef TPM_TSS_NOCRYPTO

/* NOTE: if CFB also works, do in place decryption */

static TPM_RC TSS_Response_EncryptAes(TSS_AUTH_CONTEXT *tssAuthContext,
				      struct TSS_HMAC_CONTEXT *session)
{
    TPM_RC		rc = 0;
    uint32_t 		paramSize;
    uint8_t 		*encryptParamBuffer;
    uint8_t 		*decryptParamBuffer = NULL;
    TPM2B_IV		iv;
    uint32_t           	kdfaBits;
    uint16_t		keySizeinBytes;
    uint8_t		symParmString[MAX_SYM_KEY_BYTES + MAX_SYM_BLOCK_SIZE];	/* AES key + IV */

    /* get the TPM2B parameter to decrypt */
    if (rc == 0) {
	rc = TSS_GetResponseEncryptParam(tssAuthContext,
					 &paramSize, &encryptParamBuffer);
    }
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptAes: encrypt in",
				      encryptParamBuffer, paramSize);
    }    
    if (rc == 0) {
	rc = TSS_Malloc(&decryptParamBuffer, paramSize);	/* freed @1 */
    }
    /* generate the encryption key and IV */
    /* 21.3	CFB Mode Parameter Encryption

       KDFa (hashAlg, sessionValue, "CFB", nonceNewer, nonceOlder, bits)	(34)
    */
    if (rc == 0) {
	
	iv.t.size = TSS_Sym_GetBlockSize(session->symmetric.algorithm,
					 session->symmetric.keyBits.aes);
	/* generate random values for both the AES key and the IV */
	kdfaBits = session->symmetric.keyBits.aes + (iv.t.size * 8);

	if (tssVverbose) printf("TSS_Response_EncryptAes: hashAlg %04x\n",
				session->authHashAlg);
	if (tssVverbose) printf("TSS_Response_EncryptAes: AES key bits %u\n",
				session->symmetric.keyBits.aes);
	if (tssVverbose) printf("TSS_Response_EncryptAes: kdfaBits %04x\n",
				kdfaBits);
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptAes: session key",
				      session->sessionKey.b.buffer, session->sessionKey.b.size);
	
	rc = TSS_KDFA(&symParmString[0],
		      session->authHashAlg,
		      &session->sessionValue.b,
		      "CFB",
		      &session->nonceTPM.b,
		      &session->nonceCaller.b,
		      kdfaBits);
    }
    /* copy the latter part of the kdf output to the IV */
    if (rc == 0) {
	keySizeinBytes = session->symmetric.keyBits.aes / 8;
	memcpy(iv.t.buffer, &symParmString[keySizeinBytes], iv.t.size);
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptAes: IV",
				      iv.t.buffer, iv.t.size);
    }
    /* AES CFB decrypt the response */
    if (rc == 0) {
	TPM_RC crc;
	crc = TSS_AES_DecryptCFB(decryptParamBuffer,			/* output */
				 session->symmetric.keyBits.aes,	/* 128 */
				 symParmString,				/* key */
				 iv.t.buffer,				/* IV */
				 paramSize,				/* length */
				 (uint8_t *)encryptParamBuffer);	/* input */
	if (crc != 0) {
	    if (tssVerbose) printf("TSS_Response_EncryptAes: AES decrypt failed\n");
	    rc = TSS_RC_AES_DECRYPT_FAILURE;
	}
    }		 
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_Response_EncryptAes: decrypt out",
				      decryptParamBuffer, paramSize);
    }
    if (rc == 0) {
	rc = TSS_SetResponseDecryptParam(tssAuthContext,
					 paramSize, decryptParamBuffer);
    }
    free(decryptParamBuffer);	/* @1 */
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

/*
  Command Change Authorization Processor
*/

#ifndef TPM_TSS_NOCRYPTO

static TPM_RC TSS_Command_ChangeAuthProcessor(TSS_CONTEXT *tssContext,
					      struct TSS_HMAC_CONTEXT *session,
					      size_t handleNumber,
					      COMMAND_PARAMETERS *in)
{
    TPM_RC 			rc = 0;
    size_t 			index;
    int 			found;
    TSS_ChangeAuthFunction_t 	changeAuthFunction = NULL;

    TPM_CC commandCode = TSS_GetCommandCode(tssContext->tssAuthContext);

    /* search the table for a change authorization processing function */
    if (rc == 0) {
	found = FALSE;
	for (index = 0 ; (index < (sizeof(tssTable) / sizeof(TSS_TABLE))) && !found ; index++) {
	    if (tssTable[index].commandCode == commandCode) {
		found = TRUE;
		break;	/* don't increment index if found */
	    }
	}
    }
    /* found false means there is no change authorization function.  This permits the table to be
       smaller if desired. */
    if ((rc == 0) && found) {
	changeAuthFunction = tssTable[index].changeAuthFunction;
	/* there could also be an entry that is currently NULL, nothing to do */
	if (changeAuthFunction == NULL) {
	    found = FALSE;
	}
    }
    /* call the processing function */
    if ((rc == 0) && found) {
	rc = changeAuthFunction(tssContext, session, handleNumber, in);
    }
    return rc;
}

#endif	/* TPM_TSS_NOCRYPTO */

static TPM_RC TSS_CA_HierarchyChangeAuth(TSS_CONTEXT *tssContext,
					 struct TSS_HMAC_CONTEXT *session,
					 size_t handleNumber,
					 HierarchyChangeAuth_In *in)
{
    TPM_RC 		rc = 0;
    char		*password = NULL;
    
    if (tssVverbose) printf("TSS_CA_HierarchyChangeAuth\n");
    if (in->newAuth.t.size == 0) {
	password = NULL;
    }
    else {
	if (rc == 0) {
	    rc = TSS_Malloc((uint8_t **)&password,	/* freed @1 */
			    in->newAuth.t.size + 1);
	}
	if (rc == 0) {
	    /* copy the password */
	    memcpy(password, in->newAuth.t.buffer, in->newAuth.t.size);
	    password[in->newAuth.t.size] = '\0';	/* nul terminate string */
	}
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_HmacSession_SetHmacKey(tssContext,
					session,
					handleNumber,
					password);
    }
#else
    tssContext = tssContext;
    session = session;
    handleNumber = handleNumber;
#endif	/* TPM_TSS_NOCRYPTO */
    free(password);	/* @1 */
    return rc;
}

static TPM_RC TSS_CA_NV_ChangeAuth(TSS_CONTEXT *tssContext,
				   struct TSS_HMAC_CONTEXT *session,
				   size_t handleNumber,
				   NV_ChangeAuth_In *in)
{
    TPM_RC 		rc = 0;
    char		*password = NULL;

    if (tssVverbose) printf("TSS_CA_NV_ChangeAuth\n");
    if (in->newAuth.t.size == 0) {
	password = NULL;
    }
    else {
	if (rc == 0) {
	    rc = TSS_Malloc((uint8_t **)&password,	/* freed @1 */
			    in->newAuth.t.size + 1);
	}
	if (rc == 0) {
	    /* copy the password */
	    memcpy(password, in->newAuth.t.buffer, in->newAuth.t.size);
	    password[in->newAuth.t.size] = '\0';	/* nul terminate string */
	}
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_HmacSession_SetHmacKey(tssContext,
					session,
					handleNumber,
					password);
    }
#else
    tssContext = tssContext;
    session = session;
    handleNumber = handleNumber;
#endif	/* TPM_TSS_NOCRYPTO */
    free(password);	/* @1 */
    return rc;
}

static TPM_RC TSS_CA_NV_UndefineSpaceSpecial(TSS_CONTEXT *tssContext,
					     struct TSS_HMAC_CONTEXT *session,
					     size_t handleNumber,
					     NV_UndefineSpaceSpecial_In *in)
{
    TPM_RC 		rc = 0;
    
    in = in;
    if (tssVverbose) printf("TSS_CA_NV_UndefineSpaceSpecial\n");
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	/* the nvIndex authorization, the zeroth authorization, has special handling */
	if (handleNumber == 0) {
	    /* the Empty Buffer is used as the authValue when generating the response HMAC */
	    rc = TSS_HmacSession_SetHmacKey(tssContext,
					    session,
					    handleNumber,
					    NULL);		/* password */
	}
    }
#else
    tssContext = tssContext;
    session = session;
    handleNumber = handleNumber;
#endif	/* TPM_TSS_NOCRYPTO */
    return rc;
}

#ifdef TPM_TSS_NODEPRECATEDALGS
static TPM_RC TSS_Command_CheckParameters(TPM_CC commandCode,
					  COMMAND_PARAMETERS *in)
{
    TPM_RC 				rc = 0;
    size_t 				index;
    int 				found;
    TSS_CheckParametersFunction_t	checkParametersFunction = NULL;

    /* search the table for a check parameters function */
    if (rc == 0) {
	found = FALSE;
	for (index = 0 ; (index < (sizeof(tssChTable) / sizeof(TSS_CH_TABLE))) && !found ; index++) {
	    if (tssChTable[index].commandCode == commandCode) {
		found = TRUE;
		break;	/* don't increment index if found */
	    }
	}
    }
    /* found false means there is no check parameters function.  This permits the table to be smaller
       if desired. */
    if ((rc == 0) && found) {
	checkParametersFunction = tssChTable[index].checkParametersFunction;
	/* call the check parameters function if there is one */
	if (checkParametersFunction != NULL) {
	    rc = checkParametersFunction(in);
	}
    }
    return rc;
}
#endif

/*
  Command Pre-Processor
*/

static TPM_RC TSS_Command_PreProcessor(TSS_CONTEXT *tssContext,
				       TPM_CC commandCode,
				       COMMAND_PARAMETERS *in,
				       EXTRA_PARAMETERS *extra)
{
    TPM_RC 			rc = 0;
    size_t 			index;
    int 			found;
    TSS_PreProcessFunction_t 	preProcessFunction = NULL;
    
    /* search the table for a pre-processing function */
    if (rc == 0) {
	found = FALSE;
	for (index = 0 ; (index < (sizeof(tssTable) / sizeof(TSS_TABLE))) && !found ; index++) {
	    if (tssTable[index].commandCode == commandCode) {
		found = TRUE;
		break;	/* don't increment index if found */
	    }
	}
    }
    /* found false means there is no pre-processing function.  This permits the table to be smaller
       if desired. */
    if ((rc == 0) && found) {
	preProcessFunction = tssTable[index].preProcessFunction;
	/* call the pre processing function if there is one */
	if (preProcessFunction != NULL) {
	    rc = preProcessFunction(tssContext, in, extra);
	}
    }
#ifndef TPM_TSS_NO_PRINT
    if ((rc == 0) && tssVverbose) {
	found = FALSE;
	for (index = 0 ;
	     (index < (sizeof(tssPrintTable) / sizeof(TSS_PRINT_TABLE))) && !found ;
	     index++) {
	    if (tssPrintTable[index].commandCode == commandCode) {
		found = TRUE;
		break;	/* don't increment index if found */
	    }
	}
    }
    /* found false means there is no print function.  This permits the table to be smaller
       if desired. */
    if ((rc == 0) && tssVverbose && found) {
	TSS_InPrintFunction_t inPrintFunction = tssPrintTable[index].inPrintFunction;
	/* call the pre processing function if there is one */
	if (inPrintFunction != NULL) {
	    printf("TSS_Command_PreProcessor: Input parameters\n");
	    inPrintFunction(in, 8);	/* hard code indent 8 */
	}
    }
#endif /* TPM_TSS_NO_PRINT */
    return rc;
}

/*
  Command specific pre processing functions
*/

/* TSS_PR_StartAuthSession handles StartAuthSession pre processing.

   If the salt key in->tpmKey is not NULL and an RSA key, the preprocessor supplies the encrypted
   salt.  It passes the unencrypted salt to the post processor for session key processing.

   An input salt (encrypted or unencrypted) is ignored.

   Returns an error if the key is not an RSA key.
*/

static TPM_RC TSS_PR_StartAuthSession(TSS_CONTEXT *tssContext,
				      StartAuthSession_In *in,
				      StartAuthSession_Extra *extra)
{
    TPM_RC 			rc = 0;
    
    if (tssVverbose) printf("TSS_PR_StartAuthSession\n");

    /* if (tssVverbose) StartAuthSession_In_Print(in, 8); */
    
#ifndef TPM_TSS_NOCRYPTO
    /* generate nonceCaller */
    if (rc == 0) {
	/* the size is determined by the session hash algorithm */
	in->nonceCaller.t.size = TSS_GetDigestSize(in->authHash);
	if (in->nonceCaller.t.size == 0) {
	    if (tssVerbose) printf("TSS_PR_StartAuthSession: hash algorithm %04x not implemented\n",
				   in->authHash);
	    rc = TSS_RC_BAD_HASH_ALGORITHM;
	}
    }
    if (rc == 0) {
	rc = TSS_RandBytes((unsigned char *)&in->nonceCaller.t.buffer, in->nonceCaller.t.size);
    }
#else
    in->nonceCaller.t.size = 16;
    memset(&in->nonceCaller.t.buffer, 0, 16);
#endif	/* TPM_TSS_NOCRYPTO */
	/* initialize to handle unsalted session */
    in->encryptedSalt.t.size = 0;
    if (extra != NULL) {		/* extra NULL is handled at the port processor */
	extra->salt.t.size = 0;
    }
    /* if the caller requests a salted session */
    if (in->tpmKey != TPM_RH_NULL) {
#ifndef TPM_TSS_NOCRYPTO
	TPM2B_PUBLIC		bPublic;
	
	if (rc == 0) {
	    if (extra == NULL) {
		if (tssVerbose)
		    printf("TSS_PR_StartAuthSession: salt session requires extra parameter\n");
		rc = TSS_RC_NULL_PARAMETER;
	    }
	}
	/* get the tpmKey public key */
	if (rc == 0) {
	    rc = TSS_Public_Load(tssContext, &bPublic, in->tpmKey, NULL);
	}
	/* generate the salt and encrypted salt based on the asymmetric key type */
	if (rc == 0) {
	    switch (bPublic.publicArea.type) {
#ifndef TPM_TSS_NOECC
	      case TPM_ALG_ECC:
		rc = TSS_ECC_Salt(&extra->salt,
				  &in->encryptedSalt,
				  &bPublic.publicArea);
		break;
#endif	/* TPM_TSS_NOECC */
#ifndef TPM_TSS_NORSA
	      case TPM_ALG_RSA:
		rc = TSS_RSA_Salt(&extra->salt,
				  &in->encryptedSalt,
				  &bPublic.publicArea);
		break;
#endif 	/* TPM_TSS_NORSA */
	      default:
		if (tssVerbose)
		    printf("TSS_PR_StartAuthSession: public key type %04x not supported\n",
			   bPublic.publicArea.type);
		rc = TSS_RC_BAD_SALT_KEY;
	    }
	}
#else
	tssContext = tssContext;
	rc = TSS_RC_NOT_IMPLEMENTED;
#endif	/* TPM_TSS_NOCRYPTO */
    }
    return rc;
}

#ifndef TPM_TSS_NOCRYPTO
#ifndef TPM_TSS_NORSA

/* TSS_RSA_Salt() returns both the plaintext and excrypted salt, based on the salt key bPublic. */

static TPM_RC TSS_RSA_Salt(TPM2B_DIGEST 		*salt,
			   TPM2B_ENCRYPTED_SECRET	*encryptedSalt,
			   TPMT_PUBLIC			*publicArea)
{
    TPM_RC		rc = 0;

    if (rc == 0) {
	{
	    /* error conditions when true */
	    int b1 = publicArea->type != TPM_ALG_RSA;
	    int b2 = publicArea->objectAttributes.val & TPMA_OBJECT_SIGN;
	    int b3 = !(publicArea->objectAttributes.val & TPMA_OBJECT_DECRYPT);
	    int b4 = (publicArea->parameters.rsaDetail.exponent != 0) &&
		     /* some HW TPMs return 010001 for the RSA EK with the default IWG template */
		     (publicArea->parameters.rsaDetail.exponent != RSA_DEFAULT_PUBLIC_EXPONENT);
	    /* TSS support checks */
	    if (b1 || b2 || b3 || b4) {
		if (tssVerbose)
		    printf("TSS_RSA_Salt: public key attributes not supported\n");
		rc = TSS_RC_BAD_SALT_KEY;
	    }
	}
    }    
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_RSA_Salt: public key",
				      publicArea->unique.rsa.t.buffer,
				      publicArea->unique.rsa.t.size);
    }
    /* generate a salt */
    if (rc == 0) {
	/* The size of the secret value is limited to the size of the digest produced by the
	   nameAlg of the object that is associated with the public key used for OAEP
	   encryption. */
	salt->t.size = TSS_GetDigestSize(publicArea->nameAlg);
	if (tssVverbose) printf("TSS_RSA_Salt: "
				"Hash algorithm %04x Salt size %u\n",
				publicArea->nameAlg, salt->t.size);
	/* place the salt in extra so that it can be retrieved by post processor */
	rc = TSS_RandBytes((uint8_t *)&salt->t.buffer, salt->t.size);
    }
    /* In TPM2_StartAuthSession(), when tpmKey is an RSA key, the secret value (salt) is
       encrypted using OAEP as described in B.4. The string "SECRET" (see 4.5) is used as
       the L value and the nameAlg of the encrypting key is used for the hash algorithm. The
       data value in OAEP-encrypted blob (salt) is used to compute sessionKey. */
    if (rc == 0) {
	if (tssVverbose) TSS_PrintAll("TSS_RSA_Salt: salt",
				      (uint8_t *)&salt->t.buffer,
				      salt->t.size);
    }
    /* encrypt the salt */
    if (rc == 0) {
	/* public exponent */
	unsigned char earr[3] = {0x01, 0x00, 0x01};
	/* encrypt the salt with the tpmKey public key */
	rc = TSS_RSAPublicEncrypt((uint8_t *)&encryptedSalt->t.secret,   /* encrypted data */
				  publicArea->unique.rsa.t.size,  /* size of encrypted data buffer */
				  (uint8_t *)&salt->t.buffer, /* decrypted data */
				  salt->t.size,
				  publicArea->unique.rsa.t.buffer,  /* public modulus */
				  publicArea->unique.rsa.t.size,
				  earr, 		/* public exponent */
				  sizeof(earr),
				  (unsigned char *)"SECRET",	/* encoding parameter */
				  sizeof("SECRET"),
				  publicArea->nameAlg);
    }    
    if (rc == 0) {
	encryptedSalt->t.size = publicArea->unique.rsa.t.size;
	if (tssVverbose) TSS_PrintAll("TSS_RSA_Salt: RSA encrypted salt",
				      encryptedSalt->t.secret,
				      encryptedSalt->t.size);
    }
    return rc;
}

#endif /* TPM_TSS_NORSA */
#endif /* TPM_TSS_NOCRYPTO */

static TPM_RC TSS_PR_NV_DefineSpace(TSS_CONTEXT *tssContext,
				    NV_DefineSpace_In *in,
				    void *extra)
{
    TPM_RC 	rc = 0;
    tssContext = tssContext;
    extra = extra;

    if (tssVverbose) printf("TSS_PR_NV_DefineSpace\n");
    /* Test that TPMA_NVA_POLICY_DELETE is only set when a policy is also set.  Otherwise, the index
       cannot ever be deleted, even with Platform Authorization. If the application really wants to
       do this, set the policy to one that cannot be satisfied, e.g., all 0xff's. */
    if (rc == 0) {
	if (in->publicInfo.nvPublic.attributes.val & TPMA_NVA_POLICY_DELETE) {
	    if (in->publicInfo.nvPublic.authPolicy.b.size == 0) {
		if (tssVverbose) printf("TSS_PR_NV_DefineSpace POLICY_DELETE requires a policy\n");
		rc = TSS_RC_IN_PARAMETER;
	    }
	}
    }
    return rc;
}

/*
  Response Post Processor
*/

/* TSS_Response_PostProcessor() handles any response specific post processing
 */

static TPM_RC TSS_Response_PostProcessor(TSS_CONTEXT *tssContext,
					 COMMAND_PARAMETERS *in,
					 RESPONSE_PARAMETERS *out,
					 EXTRA_PARAMETERS *extra)
{
    TPM_RC 			rc = 0;
    size_t 			index;
    int 			found;
    TSS_PostProcessFunction_t 	postProcessFunction = NULL;

    /* search the table for a post processing function */
    if (rc == 0) {
	TPM_CC commandCode = TSS_GetCommandCode(tssContext->tssAuthContext);
	found = FALSE;
	for (index = 0 ; (index < (sizeof(tssTable) / sizeof(TSS_TABLE))) && !found ; index++) {
	    if (tssTable[index].commandCode == commandCode) {
		found = TRUE;
		break;	/* don't increment index if found */
	    }
	}
    }
    /* found false means there is no post processing function.  This permits the table to be smaller
       if desired. */
    if ((rc == 0) && found) {
	postProcessFunction = tssTable[index].postProcessFunction;
	/* there could also be an entry that it currently NULL, nothing to do */
	if (postProcessFunction == NULL) {
	    found = FALSE;
	}
    }
    /* call the function */
    if ((rc == 0) && found) {
	rc = postProcessFunction(tssContext, in, out, extra);
    }
    return rc;
}

/*
  Command specific post processing functions
*/

/* TSS_PO_StartAuthSession handles StartAuthSession post processing.  It:

   creates a TSS HMAC session

   saves the session handle, hash algorithm, and symmetric algorithm, nonceCaller and nonceTPM
   
   It calculates the session key and saves it

   Finally, it marshals the session and stores it
*/

static TPM_RC TSS_PO_StartAuthSession(TSS_CONTEXT *tssContext,
				      StartAuthSession_In *in,
				      StartAuthSession_Out *out,
				      StartAuthSession_Extra *extra)
{
    TPM_RC 			rc = 0;
    struct TSS_HMAC_CONTEXT 	*session = NULL;
    TPM2B_DIGEST 		salt;
    
    if (tssVverbose) printf("TSS_PO_StartAuthSession\n");
    /* allocate a TSS_HMAC_CONTEXT session context */
    if (rc == 0) {
	rc = TSS_HmacSession_GetContext(&session);
    }
    if (rc == 0) {
	session->sessionHandle = out->sessionHandle;
	session->authHashAlg = in->authHash;
#ifndef TPM_TSS_NOCRYPTO
	session->sizeInBytes = TSS_GetDigestSize(session->authHashAlg);
#endif
	session->symmetric = in->symmetric;
	session->sessionType = in->sessionType;
    }
    /* if not a bind session or if no bind password was supplied */
    if (rc == 0) {
	if ((extra == NULL) || (in->bind == TPM_RH_NULL) || (extra->bindPassword == NULL)) {
	    session->bindAuthValue.b.size = 0;
	}
	else {
	    rc = TSS_TPM2B_StringCopy(&session->bindAuthValue.b,
				      extra->bindPassword, sizeof(session->bindAuthValue.t.buffer));
	}
    }
    if (rc == 0) {
	/* if the caller did not supply extra, the salt must be empty */
	if (extra == NULL) {
	    salt.b.size = 0;
	}
	/* if the caller supplied extra, the preprocessor sets salt to empty (unsalted) or the
	   plaintext salt value */
	else {
	    rc = TSS_TPM2B_Copy(&salt.b, &extra->salt.b, sizeof(TPMT_HA));
	}
    }
#ifndef TPM_TSS_NOCRYPTO
    if (rc == 0) {
	rc = TSS_TPM2B_Copy(&session->nonceTPM.b, &out->nonceTPM.b, sizeof(TPMT_HA));
    }
    if (rc == 0) {
	rc = TSS_TPM2B_Copy(&session->nonceCaller.b, &in->nonceCaller.b, sizeof(TPMT_HA));
    }
    if (rc == 0) {
	rc = TSS_HmacSession_SetSessionKey(tssContext, session,
					   &salt,
					   in->bind, &session->bindAuthValue);
    }
#endif	/* TPM_TSS_NOCRYPTO */
    if (rc == 0) {
	rc = TSS_HmacSession_SaveSession(tssContext, session);
    }
    TSS_HmacSession_FreeContext(session);
    return rc;
}

/* TSS_PO_ContextSave() saves the name of an object in a filename that is a hash of the contextBlob.

   This permits the name to be found during ContextLoad.
*/

static TPM_RC TSS_PO_ContextSave(TSS_CONTEXT *tssContext,
				 ContextSave_In *in,
				 ContextSave_Out *out,
				 void *extra)
{
    TPM_RC 		rc = 0;
#ifndef TPM_TSS_NOFILE
    TPMT_HA 		cpHash;		/* largest size of a digest */
    char		string[65];	/*  sha256 hash * 2 + 1 */
    TPM_HT 		handleType;
    int			done = FALSE;
#endif

    in = in;
    extra = extra;

#ifndef TPM_TSS_NOFILE
    if (tssVverbose) printf("TSS_PO_ContextSave: handle %08x\n", in->saveHandle);
    /* only for objects and sequence objects, not sessions */
    if (rc == 0) {
	handleType = (TPM_HT) ((in->saveHandle & HR_RANGE_MASK) >> HR_SHIFT);
	if (handleType != TPM_HT_TRANSIENT) {
	    done = TRUE;
	}
    }
    if ((rc == 0) && !done) {
	cpHash.hashAlg = TPM_ALG_SHA256;	/* arbitrary choice */
	rc = TSS_Hash_Generate(&cpHash,
			       out->context.contextBlob.b.size, out->context.contextBlob.b.buffer,
			       0, NULL);
    }
    /* convert a hash of the context blob to a string */
    if ((rc == 0) && !done) {
	rc = TSS_HashToString(string, cpHash.digest.sha256);
    }
    if ((rc == 0) && !done) {
	rc = TSS_Name_Copy(tssContext,
			   0, string,			/* to context */
			   in->saveHandle, NULL);	/* from handle */
    }
    /* get the public key of the object being context saved */
    /* save the public key under the context */
    if ((rc == 0) && !done) {
	rc = TSS_Public_Copy(tssContext,
			     0,
			     string,
			     in->saveHandle,
			     NULL);
    }
#else
    tssContext = tssContext;
    out = out;
#endif
    return rc;
}

static TPM_RC TSS_PO_ContextLoad(TSS_CONTEXT *tssContext,
				 ContextLoad_In *in,
				 ContextLoad_Out *out,
				 void *extra)
{
    TPM_RC 		rc = 0;
#ifndef TPM_TSS_NOFILE
    TPMT_HA 		cpHash;		/* largest size of a digest */
    char		string[65];	/*  sha256 hash * 2 + 1 */
    TPM_HT 		handleType;
    int			done = FALSE;
#endif

    out = out;
    extra = extra;

#ifndef TPM_TSS_NOFILE
    if (tssVverbose) printf("TSS_PO_ContextLoad: handle %08x\n", out->loadedHandle);
    /* only for objects and sequence objects, not sessions */
    if (rc == 0) {
	handleType = (TPM_HT) ((out->loadedHandle & HR_RANGE_MASK) >> HR_SHIFT);
	if (handleType != TPM_HT_TRANSIENT) {
	    done = TRUE;
	}
    }
    if ((rc == 0) && !done) {
	cpHash.hashAlg = TPM_ALG_SHA256;	/* arbitrary choice */
	rc = TSS_Hash_Generate(&cpHash,
			       in->context.contextBlob.b.size, in->context.contextBlob.b.buffer,
			       0, NULL);
    }
    /* convert a hash of the context blob to a string */
    if ((rc == 0) && !done) {
	rc = TSS_HashToString(string, cpHash.digest.sha256);
    }
    /* get the Name of the object being context loaded */
    /* write the name with the loaded context's handle */
    if ((rc == 0) && !done) {
	rc = TSS_Name_Copy(tssContext,
			   out->loadedHandle, NULL,	/* to handle */
			   0, string);			/* from context */	
    }
    /* get the public key of the object being context loaded */
    /* write the public key with the loaded context's handle */
    if ((rc == 0) && !done) {
	rc = TSS_Public_Copy(tssContext,
			     out->loadedHandle,
			     NULL,
			     0,
			     string);
    }
#else
    tssContext = tssContext;
    in = in; 
#endif
    return rc;
}

/* TSS_HashToString() converts a SHA-256 binary hash (really any 32-byte value) to a string 

   string must be 65 bytes: 32*2 + 1

   NOTE: Hard coded to SHA256
*/

#ifndef TPM_TSS_NOFILE

static TPM_RC TSS_HashToString(char *str, uint8_t *digest)
{
    size_t i;

    for (i = 0 ; i < SHA256_DIGEST_SIZE ; i++) {
	sprintf(str +(i*2), "%02x", digest[i]);
    }
    if (tssVverbose) printf("TSS_HashToString: %s\n", str);
    return 0;
}

#endif

/* TSS_PO_FlushContext() removes persistent state associated with the handle */

static TPM_RC TSS_PO_FlushContext(TSS_CONTEXT *tssContext,
				  FlushContext_In *in,
				  void *out,
				  void *extra)
{
    TPM_RC 			rc = 0;

    out = out;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_FlushContext: flushHandle %08x\n", in->flushHandle);
    if (rc == 0) {
	rc = TSS_DeleteHandle(tssContext, in->flushHandle);
    }
    return rc;
}

/* TSS_PO_EvictControl() removes persistent state associated with the handle */

static TPM_RC TSS_PO_EvictControl(TSS_CONTEXT *tssContext,
				  EvictControl_In *in,
				  void *out,
				  void *extra)
{
    TPM_RC 			rc = 0;

    out = out;
    extra = extra;
    
    if (tssVverbose) printf("TSS_PO_EvictControl: object %08x persistent %08x\n",
			    in->objectHandle, in->persistentHandle);
    /* if it successfully made a persistent copy */
    if (in->objectHandle != in->persistentHandle) {
	/* TPM2B_PUBLIC	bPublic; */
	if (rc == 0) {
	    rc = TSS_Name_Copy(tssContext,
			       in->persistentHandle, NULL,	/* to persistent handle */
			       in->objectHandle, NULL);		/* from transient handle */	
	}
	/* get the transient object public key */
	/* copy it to the persistent object public key */
	if (rc == 0) {
	    rc = TSS_Public_Copy(tssContext,
				 in->persistentHandle,
				 NULL,
				 in->objectHandle,
				 NULL);
	}
    }
    /* if it successfully evicted the persistent object */
    else {
	if (rc == 0) {
	    rc = TSS_DeleteHandle(tssContext, in->persistentHandle);
	}
    }
    return rc;
}

/* TSS_PO_Load() saves the Name returned for the loaded object.  It saves the TPM2B_PUBLIC */

static TPM_RC TSS_PO_Load(TSS_CONTEXT *tssContext,
			  Load_In *in,
			  Load_Out *out,
			  void *extra)
{
    TPM_RC 	rc = 0;

    in = in;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_Load: handle %08x\n", out->objectHandle);
    /* use handle as file name */
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &out->name, out->objectHandle, NULL);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &in->inPublic, out->objectHandle, NULL);
    }
    return rc;
}

/* TSS_PO_LoadExternal() saves the Name returned for the loaded object */

static TPM_RC TSS_PO_LoadExternal(TSS_CONTEXT *tssContext,
				  LoadExternal_In *in,
				  LoadExternal_Out *out,
				  void *extra)
{
    TPM_RC 	rc = 0;

    in = in;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_LoadExternal: handle %08x\n", out->objectHandle);
    /* use handle as file name */
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &out->name, out->objectHandle, NULL);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &in->inPublic, out->objectHandle, NULL);
    }
    return rc;
}

/* TSS_PO_ReadPublic() saves the Name returned for the loaded object */

static TPM_RC TSS_PO_ReadPublic(TSS_CONTEXT *tssContext,
				ReadPublic_In *in,
				ReadPublic_Out *out,
				void *extra)
{
    TPM_RC 	rc = 0;

    in = in;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_ReadPublic: handle %08x\n", in->objectHandle);
    /* if the TSS is compiled without crypto support, it cannot recalculate the Name from the public
       area. It has to trust the response from the TPM.  This should be OK since a 'no crypto' TSS
       is used when there is a tructed path to the TPM. */
#ifndef TPM_TSS_NOCRYPTO
    /* validate the Name against the public area */
    /* Name = nameAlg || HnameAlg (handle->publicArea)
       where
       nameAlg	algorithm used to compute Name
       HnameAlg	hash using the nameAlg parameter in the object associated with handle
       publicArea 	contents of the TPMT_PUBLIC associated with handle
    */
    {
	TPM2B_NAME name;
	if (rc == 0) {
	    rc = TSS_ObjectPublic_GetName(&name, &out->outPublic.publicArea);
	}
	if (rc == 0) {
	    if (name.t.size != out->name.t.size) {
		if (tssVerbose)
		    printf("TSS_PO_ReadPublic: TPMT_PUBLIC does not match TPM2B_NAME\n");
		rc = TSS_RC_MALFORMED_PUBLIC;
	    }
	    else {
		int irc;
		irc = memcmp(name.t.name, out->name.t.name, out->name.t.size);
		if (irc != 0) {
		    if (tssVerbose)
			printf("TSS_PO_ReadPublic: TPMT_PUBLIC does not match TPM2B_NAME\n");
		    rc = TSS_RC_MALFORMED_PUBLIC;
		}
	    }
	}
    }
#endif
    /* use handle as file name */
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &out->name, in->objectHandle, NULL);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &out->outPublic, in->objectHandle, NULL);
    }
    return rc;
}

/* TSS_PO_Load() saves the Name returned for the loaded object.  It saves the TPM2B_PUBLIC */

static TPM_RC TSS_PO_CreateLoaded(TSS_CONTEXT *tssContext,
				  CreateLoaded_In *in,
				  CreateLoaded_Out *out,
				  void *extra)
{
    TPM_RC 	rc = 0;

    in = in;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_CreateLoaded: handle %08x\n", out->objectHandle);
    /* use handle as file name */
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &out->name, out->objectHandle, NULL);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &out->outPublic, out->objectHandle, NULL);
    }
    return rc;
}

/* TSS_PO_HashSequenceStart() saves the Name returned for the started sequence object */

static TPM_RC TSS_PO_HashSequenceStart(TSS_CONTEXT *tssContext,
				       HashSequenceStart_In *in,
				       HashSequenceStart_Out *out,
				       void *extra)
{
    TPM_RC 	rc = 0;
    TPM2B_NAME 	name;

    in = in;
    extra = extra;

    if (tssVverbose) printf("TSS_PO_HashSequenceStart\n");
    /* Part 1 Table 3 The Name of a sequence object is an Empty Buffer */
    if (rc == 0) {
	name.b.size = 0;
	/* use handle as file name */
	rc = TSS_Name_Store(tssContext, &name, out->sequenceHandle, NULL);
    }
    return rc;
}


/* TSS_PO_HMAC_Start() saves the Name returned for the started sequence object */

static TPM_RC TSS_PO_HMAC_Start(TSS_CONTEXT *tssContext,
				HMAC_Start_In *in,
				HMAC_Start_Out *out,
				void *extra)
{
    TPM_RC 	rc = 0;
    TPM2B_NAME 	name;

    in = in;
    extra = extra;

    if (tssVverbose) printf("TSS_PO_HMAC_Start\n");
    /* Part 1 Table 3 The Name of a sequence object is an Empty Buffer */
    if (rc == 0) {
	name.b.size = 0;
	/* use handle as file name */
	rc = TSS_Name_Store(tssContext, &name, out->sequenceHandle, NULL);
    }
    return rc;
}

static TPM_RC TSS_PO_SequenceComplete(TSS_CONTEXT *tssContext,
				      SequenceComplete_In *in,
				      SequenceComplete_Out *out,
				      void *extra)
{
    TPM_RC 	rc = 0;

    out = out;
    extra = extra;

    if (tssVverbose) printf("TSS_PO_SequenceComplete: sequenceHandle %08x\n", in->sequenceHandle);
    if (rc == 0) {
	rc = TSS_DeleteHandle(tssContext, in->sequenceHandle);
    }
    return rc;
}
static TPM_RC TSS_PO_EventSequenceComplete(TSS_CONTEXT *tssContext,
					   EventSequenceComplete_In *in,
					   EventSequenceComplete_Out *out,
					   void *extra)
{
    TPM_RC 	rc = 0;
    out = out;
    extra = extra;
    if (tssVverbose)
	printf("TSS_PO_EventSequenceComplete: sequenceHandle %08x\n", in->sequenceHandle);
    if (rc == 0) {
	rc = TSS_DeleteHandle(tssContext, in->sequenceHandle);
    }
    return rc;
}

static TPM_RC TSS_PO_PolicyAuthValue(TSS_CONTEXT *tssContext,
				     PolicyAuthValue_In *in,
				     void *out,
				     void *extra)
{
    TPM_RC 			rc = 0;
    struct TSS_HMAC_CONTEXT 	*session = NULL;
    
    out = out;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_PolicyAuthValue\n");
    if (rc == 0) {
	rc = TSS_Malloc((unsigned char **)&session, sizeof(TSS_HMAC_CONTEXT));	/* freed @1 */
    }
    if (rc == 0) {
	rc = TSS_HmacSession_LoadSession(tssContext, session, in->policySession);
    }
    if (rc == 0) {
	session->isPasswordNeeded = FALSE;
	session->isAuthValueNeeded = TRUE;
	rc = TSS_HmacSession_SaveSession(tssContext, session);
    }
    free(session);		/* @1 */
    return rc;
}

static TPM_RC TSS_PO_PolicyPassword(TSS_CONTEXT *tssContext,
				    PolicyPassword_In *in,
				    void *out,
				    void *extra)
{
    TPM_RC 			rc = 0;
    struct TSS_HMAC_CONTEXT 	*session = NULL;

    out = out;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_PolicyPassword\n");
    if (rc == 0) {
	rc = TSS_Malloc((unsigned char **)&session, sizeof(TSS_HMAC_CONTEXT));	/* freed @1 */
    }
    if (rc == 0) {
	rc = TSS_HmacSession_LoadSession(tssContext, session, in->policySession);
    }
    if (rc == 0) {
	session->isPasswordNeeded = TRUE;
	session->isAuthValueNeeded = FALSE;
	rc = TSS_HmacSession_SaveSession(tssContext, session);
    }
    free(session);		/* @1 */
    return rc;
}

static TPM_RC TSS_PO_CreatePrimary(TSS_CONTEXT *tssContext,
				   CreatePrimary_In *in,
				   CreatePrimary_Out *out,
				   void *extra)
{
    TPM_RC 			rc = 0;

    in = in;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_CreatePrimary: handle %08x\n", out->objectHandle);
    /* use handle as file name */
    if (rc == 0) {
	rc = TSS_Name_Store(tssContext, &out->name, out->objectHandle, NULL);
    }
    if (rc == 0) {
	rc = TSS_Public_Store(tssContext, &out->outPublic, out->objectHandle, NULL);
    }
    return rc;
}

static TPM_RC TSS_PO_NV_DefineSpace(TSS_CONTEXT *tssContext,
				    NV_DefineSpace_In *in,
				    void *out,
				    void *extra)
{
    TPM_RC 	rc = 0;

    if (tssVverbose) printf("TSS_PO_NV_DefineSpace\n");
#ifndef TPM_TSS_NOCRYPTO
    {
	TPM2B_NAME name;
	/* calculate the Name from the input public area */
	/* Name = nameAlg || HnameAlg (handle->nvPublicArea)
	   where
	   nameAlg	algorithm used to compute Name
	   HnameAlg hash using the nameAlg parameter in the NV Index location associated with handle
	   nvPublicArea	contents of the TPMS_NV_PUBLIC associated with handle
	*/
	/* calculate the Name from the input TPMS_NV_PUBLIC */
	if (rc == 0) {
	    rc = TSS_NVPublic_GetName(&name, &in->publicInfo.nvPublic);
	}
	/* use handle as file name */
	if (rc == 0) {
	    rc = TSS_Name_Store(tssContext, &name, in->publicInfo.nvPublic.nvIndex, NULL);
	}
	if (rc == 0) {
	    rc = TSS_NVPublic_Store(tssContext, &in->publicInfo.nvPublic,
				    in->publicInfo.nvPublic.nvIndex); 
	}
    }
#else
    tssContext = tssContext;
    in = in;
#endif
    out = out;
    extra = extra;
    return rc;
}


static TPM_RC TSS_PO_NV_ReadPublic(TSS_CONTEXT *tssContext,
				   NV_ReadPublic_In *in,
				   NV_ReadPublic_Out *out,
				   void *extra)
{
    TPM_RC 	rc = 0;

    if (tssVverbose) printf("TSS_PO_NV_ReadPublic\n");
    
    /* validate the Name against the public area */
    /* Name = nameAlg || HnameAlg (handle->nvPublicArea)
       where
       nameAlg	algorithm used to compute Name
       HnameAlg hash using the nameAlg parameter in the NV Index location associated with handle
       nvPublicArea	contents of the TPMS_NV_PUBLIC associated with handle
    */
#ifndef TPM_TSS_NOCRYPTO
    {
	TPM2B_NAME name;
	/* calculate the Name from the TPMS_NV_PUBLIC */
	if (rc == 0) {
	    rc = TSS_NVPublic_GetName(&name, &out->nvPublic.nvPublic);
	}
	if (rc == 0) {
	    if (name.t.size != out->nvName.t.size) {
		if (tssVerbose)
		    printf("TSS_PO_NV_ReadPublic: TPMT_NV_PUBLIC does not match TPM2B_NAME\n");
		rc = TSS_RC_MALFORMED_NV_PUBLIC;
	    }
	    else {
		int irc;
		irc = memcmp(name.t.name, out->nvName.t.name, out->nvName.t.size);
		if (irc != 0) {
		    if (tssVerbose)
			printf("TSS_PO_NV_ReadPublic: TPMT_NV_PUBLIC does not match TPM2B_NAME\n");
		    rc = TSS_RC_MALFORMED_NV_PUBLIC;
		}
	    }
	}
	/* use handle as file name */
	if (rc == 0) {
	    rc = TSS_Name_Store(tssContext, &out->nvName, in->nvIndex, NULL);
	}
	if (rc == 0) {
	    rc = TSS_NVPublic_Store(tssContext, &out->nvPublic.nvPublic, in->nvIndex); 
	}
    }
#else
    tssContext = tssContext;
    in = in;
    out = out;
#endif
    extra = extra;
    return rc;
}

static TPM_RC TSS_PO_NV_UndefineSpace(TSS_CONTEXT *tssContext,
				      NV_UndefineSpace_In *in,
				      void *out,
				      void *extra)
{
    TPM_RC 			rc = 0;

    out = out;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_NV_UndefineSpace\n");
#ifndef TPM_TSS_NOCRYPTO
    /* Don't check return code. */
    TSS_DeleteHandle(tssContext, in->nvIndex);
    TSS_NVPublic_Delete(tssContext, in->nvIndex);
#else
    tssContext = tssContext;
    in = in;
#endif
    return rc;
}

static TPM_RC TSS_PO_NV_UndefineSpaceSpecial(TSS_CONTEXT *tssContext,
					     NV_UndefineSpaceSpecial_In *in,
					     void *out,
					     void *extra)
{
    TPM_RC 			rc = 0;

    out = out;
    extra = extra;
    if (tssVverbose) printf("TSS_PO_NV_UndefineSpaceSpecial\n");
    /* Don't check return code.  The name will only exist if NV_ReadPublic has been issued */
    TSS_DeleteHandle(tssContext, in->nvIndex);
    TSS_NVPublic_Delete(tssContext, in->nvIndex);
    return rc;
}

/* TSS_PO_NV_Write() handles the Name and NVPublic update for the 4 NV write commands: write,
   increment, extend, and setbits */

static TPM_RC TSS_PO_NV_Write(TSS_CONTEXT *tssContext,
			      NV_Write_In *in,
			      void *out,
			      void *extra)
{
    TPM_RC 			rc = 0;
    
    if (tssVverbose) printf("TSS_PO_NV_Write, Increment, Extend, SetBits:\n");

#ifndef TPM_TSS_NOCRYPTO
    {
	TPMS_NV_PUBLIC 		nvPublic;
	TPM2B_NAME 		name;		/* new name */
	
	if (rc == 0) {
	    rc = TSS_NVPublic_Load(tssContext, &nvPublic, in->nvIndex);
	}
	/* if the previous store had written clear */
	if (!(nvPublic.attributes.val & TPMA_NVA_WRITTEN)) {
	    if (rc == 0) {
		/* set the written bit */
		nvPublic.attributes.val |= TPMA_NVA_WRITTEN;
		/* save the TPMS_NV_PUBLIC */
		rc = TSS_NVPublic_Store(tssContext, &nvPublic, in->nvIndex);
	    }
	    /* calculate the name */
	    if (rc == 0) {
		rc = TSS_NVPublic_GetName(&name, &nvPublic);
	    }
	    /* save the name */
	    if (rc == 0) {
		/* use handle as file name */
		rc = TSS_Name_Store(tssContext, &name, in->nvIndex, NULL);
	    }
	    /* if there is a failure. delete the name and NVPublic */
	    if (rc != 0) {
		TSS_DeleteHandle(tssContext, in->nvIndex);
		TSS_NVPublic_Delete(tssContext, in->nvIndex);
	    }
	}
    }
#else
    tssContext = tssContext;
    in = in;
#endif
    out = out;
    extra = extra;
    return rc;
}

/* TSS_PO_NV_WriteLock() handles the Name and NVPublic update for the write lock command */

static TPM_RC TSS_PO_NV_WriteLock(TSS_CONTEXT *tssContext,
				  NV_WriteLock_In *in,
				  void *out,
				  void *extra)
{
    TPM_RC 			rc = 0;
   
    if (tssVverbose) printf("TSS_PO_NV_WriteLock:\n");

#ifndef TPM_TSS_NOCRYPTO
    {
	TPMS_NV_PUBLIC 		nvPublic;
	TPM2B_NAME 		name;		/* new name */
	
 	if (rc == 0) {
	    rc = TSS_NVPublic_Load(tssContext, &nvPublic, in->nvIndex);
	}
	/* if the previous store had write lock clear */
	if (!(nvPublic.attributes.val & TPMA_NVA_WRITELOCKED)) {
	    if (rc == 0) {
		/* set the write lock bit */
		nvPublic.attributes.val |= TPMA_NVA_WRITELOCKED;
		/* save the TPMS_NV_PUBLIC */
		rc = TSS_NVPublic_Store(tssContext, &nvPublic, in->nvIndex);
	    }
	    /* calculate the name */
	    if (rc == 0) {
		rc = TSS_NVPublic_GetName(&name, &nvPublic);
	    }
	    /* save the name */
	    if (rc == 0) {
		/* use handle as file name */
		rc = TSS_Name_Store(tssContext, &name, in->nvIndex, NULL);
	    }
	    /* if there is a failure. delete the name and NVPublic */
	    if (rc != 0) {
		TSS_DeleteHandle(tssContext, in->nvIndex);
		TSS_NVPublic_Delete(tssContext, in->nvIndex);
	    }
	}
    }
#else
    tssContext = tssContext;
    in = in;
#endif
    out = out;
    extra = extra;
    return rc;
}

/* TSS_PO_NV_WriteLock() handles the Name and NVPublic update for the read lock command */

static TPM_RC TSS_PO_NV_ReadLock(TSS_CONTEXT *tssContext,
				 NV_ReadLock_In *in,
				 void *out,
				 void *extra)
{
    TPM_RC 			rc = 0;
    
    if (tssVverbose) printf("TSS_PO_NV_ReadLock:");

#ifndef TPM_TSS_NOCRYPTO
    {
	TPMS_NV_PUBLIC 		nvPublic;
	TPM2B_NAME 			name;		/* new name */

	if (rc == 0) {
	    rc = TSS_NVPublic_Load(tssContext, &nvPublic, in->nvIndex);
	}
	/* if the previous store had read lock clear */
	if (!(nvPublic.attributes.val & TPMA_NVA_READLOCKED)) {
	    if (rc == 0) {
		/* set the read lock bit */
		nvPublic.attributes.val |= TPMA_NVA_READLOCKED;
		/* save the TPMS_NV_PUBLIC */
		rc = TSS_NVPublic_Store(tssContext, &nvPublic, in->nvIndex);
	    }
	    /* calculate the name */
	    if (rc == 0) {
		rc = TSS_NVPublic_GetName(&name, &nvPublic);
	    }
	    /* save the name */
	    if (rc == 0) {
		/* use handle as file name */
		rc = TSS_Name_Store(tssContext, &name, in->nvIndex, NULL);
	    }
	    /* if there is a failure. delete the name and NVPublic */
	    if (rc != 0) {
		TSS_DeleteHandle(tssContext, in->nvIndex);
		TSS_NVPublic_Delete(tssContext, in->nvIndex);
	    }
	}
    }
#else
    tssContext = tssContext;
    in = in;
#endif
    out = out;
    extra = extra;
    return rc;
}

