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

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifdef TPM_POSIX
#include <sys/types.h>
#include <unistd.h>
#endif

#include "tpm_admin.h"
#include "tpm_audit.h"
#include "tpm_auth.h"
#include "tpm_constants.h"
#include "tpm_commands.h"
#include "tpm_counter.h"
#include "tpm_cryptoh.h"
#include "tpm_crypto.h"
#include "tpm_daa.h"
#include "tpm_debug.h"
#include "tpm_delegate.h"
#include "tpm_error.h"
#include "tpm_identity.h"
#include "tpm_init.h"
#include "tpm_io.h"
#include "tpm_key.h"
#include "tpm_maint.h"
#include "tpm_memory.h"
#include "tpm_migration.h"
#include "tpm_nonce.h"
#include "tpm_nvram.h"
#include "tpm_owner.h"
#include "tpm_pcr.h"
#include "tpm_permanent.h"
#include "tpm_platform.h"
#include "tpm_session.h"
#include "tpm_sizedbuffer.h"
#include "tpm_startup.h"
#include "tpm_storage.h"
#include "tpm_ticks.h"
#include "tpm_transport.h"
#include "tpm_ver.h"

#include "tpm_process.h"

/* local prototypes */

/* get capabilities */

static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse,
					   uint32_t ordinal);
static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse,
					   uint32_t algorithmID);
static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse,
					   uint16_t protocolID);
static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse,
					    tpm_state_t *tpm_state,
					    uint32_t capFlag);
static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse,
						tpm_state_t *tpm_state,
						uint32_t capProperty);
static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse);
static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse,
						   const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry,
						   TPM_SIZED_BUFFER *subCap);
static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_SYM_MODE symMode);
static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse,
						 TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries,
						 uint32_t tpm_key_handle);
static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse,
					   tpm_state_t *tpm_state,
					   TPM_SIZED_BUFFER *subCap);
static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse,
					       tpm_state_t *tpm_state,
					       uint32_t nvIndex);
static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse,
						TPM_ALGORITHM_ID algorithmID);
static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse,
					      tpm_state_t *tpm_state,
					      TPM_RESOURCE_TYPE resourceType);
static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_ENC_SCHEME encScheme);
static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse,
						   uint32_t algorithmID);
static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse,
						  TPM_SIZED_BUFFER *subCap);
#if  (TPM_REVISION >= 103)	/* added for rev 103 */
static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_SIZED_BUFFER *subCap,
					       tpm_state_t *tpm_state);
#endif
static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse,
						  TPM_PERMANENT_DATA *tpm_permanent_data);

static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse);
static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse);

/* set capabilities */

static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state,
						 TPM_BOOL ownerAuthorized,
						 TPM_BOOL presenceAuthorized,
						 uint32_t subCap32,
						 TPM_BOOL valueBool);
static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state,
						TPM_BOOL ownerAuthorized,
						TPM_BOOL presenceAuthorized,
						uint32_t subCap32,
						uint32_t valueUint32);
static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state,
						    TPM_BOOL ownerAuthorized,
						    TPM_BOOL presenceAuthorized,
						    uint32_t subCap32,
						    TPM_BOOL valueBool);
static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state,
						   TPM_BOOL ownerAuthorized,
						   TPM_BOOL presenceAuthorized,
						   uint32_t subCap32,
						   uint32_t valueUint32);
static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state,
						  TPM_BOOL ownerAuthorized,
						  TPM_BOOL presenceAuthorized,
						  uint32_t subCap32,
						  TPM_BOOL valueBool);
static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state,
						 TPM_BOOL ownerAuthorized,
						 TPM_BOOL presenceAuthorized,
						 uint32_t subCap32,
						 TPM_SIZED_BUFFER *setValue);
static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state,
					      TPM_BOOL ownerAuthorized,
					      TPM_BOOL presenceAuthorized,
					      uint32_t subCap32,
					      TPM_SIZED_BUFFER *setValue);

/*
  TPM_CAP_VERSION_INFO
*/

/* TPM_CapVersionInfo_Init()

   sets members to default values
   sets all pointers to NULL and sizes to 0
   always succeeds - no return code
*/

void TPM_CapVersionInfo_Init(TPM_CAP_VERSION_INFO *tpm_cap_version_info)
{
    printf(" TPM_CapVersionInfo_Init:\n");
    TPM_Version_Init(&(tpm_cap_version_info->version));
    tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL;
    tpm_cap_version_info->errataRev = TPM_ERRATA_REV;
    memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID,
	   sizeof(tpm_cap_version_info->tpmVendorID));
    tpm_cap_version_info->vendorSpecificSize = 0;
    tpm_cap_version_info->vendorSpecific = NULL;
    return;
}

/* TPM_CapVersionInfo_Set() sets members to software specific data */

void TPM_CapVersionInfo_Set(TPM_CAP_VERSION_INFO *tpm_cap_version_info,
			    TPM_PERMANENT_DATA *tpm_permanent_data)
{
    printf(" TPM_CapVersionInfo_Set:\n");
    TPM_Version_Set(&(tpm_cap_version_info->version), tpm_permanent_data);
    tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL;
    tpm_cap_version_info->errataRev = TPM_ERRATA_REV;
    memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID,
	   sizeof(tpm_cap_version_info->tpmVendorID));
    tpm_cap_version_info->vendorSpecificSize = 0;
    tpm_cap_version_info->vendorSpecific = NULL;
    return;
}

#if 0	/* not required */
/* TPM_CapVersionInfo_Load()

   deserialize the structure from a 'stream'
   'stream_size' is checked for sufficient data
   returns 0 or error codes
   
   Before use, call TPM_CapVersionInfo_Init() or TPM_CapVersionInfo_Set()
   After use, call TPM_CapVersionInfo_Delete() to free memory
*/

TPM_RESULT TPM_CapVersionInfo_Load(TPM_CAP_VERSION_INFO *tpm_cap_version_info,
				   unsigned char **stream,
				   uint32_t *stream_size)
{
    TPM_RESULT		rc = 0;

    printf(" TPM_CapVersionInfo_Load:\n");
    /* check tag */
    if (rc == 0) {
	rc = TPM_CheckTag(TPM_TAG_CAP_VERSION_INFO, stream, stream_size);
    }
    /* load version */
    if (rc == 0) {
	rc = TPM_Version_Load(&(tpm_cap_version_info->version), stream, stream_size);
    }
    /* load specLevel */
    if (rc == 0) {
	rc = TPM_Load16(&(tpm_cap_version_info->specLevel), stream, stream_size);
    }
    /* load errataRev */
    if (rc == 0) {
	rc = TPM_Loadn(&(tpm_cap_version_info->errataRev), sizeof(tpm_cap_version_info->errataRev),
		       stream, stream_size);
    }
    /* load tpmVendorID */
    if (rc == 0) {
	rc = TPM_Loadn(tpm_cap_version_info->tpmVendorID, sizeof(tpm_cap_version_info->tpmVendorID),
		       stream, stream_size);
    }
    /* load vendorSpecificSize */
    if (rc == 0) {
	rc = TPM_Load16(&(tpm_cap_version_info->vendorSpecificSize), stream, stream_size);
    }
    /* allocate memory for vendorSpecific */
    if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) {
	rc = TPM_Malloc(&(tpm_cap_version_info->vendorSpecific),
			tpm_cap_version_info->vendorSpecificSize);
    }
    /* load vendorSpecific */
    if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) {
	rc = TPM_Loadn(tpm_cap_version_info->vendorSpecific,
		       tpm_cap_version_info->vendorSpecificSize,
		       stream, stream_size);
    }
    return rc;
}
#endif

/* TPM_CapVersionInfo_Store()
   
   serialize the structure to a stream contained in 'sbuffer'
   returns 0 or error codes
*/

TPM_RESULT TPM_CapVersionInfo_Store(TPM_STORE_BUFFER *sbuffer,
				    const TPM_CAP_VERSION_INFO *tpm_cap_version_info)
{
    TPM_RESULT		rc = 0;

    printf(" TPM_CapVersionInfo_Store:\n");
    /* store tag */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CAP_VERSION_INFO); 
    }
    /* store version */
    if (rc == 0) {
	rc = TPM_Version_Store(sbuffer, &(tpm_cap_version_info->version));
    }
    /* store specLevel */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->specLevel);
    }
    /* store errataRev */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append(sbuffer, &(tpm_cap_version_info->errataRev),
				sizeof(tpm_cap_version_info->errataRev));
    }
    /* store tpmVendorID */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append(sbuffer, tpm_cap_version_info->tpmVendorID,
				sizeof(tpm_cap_version_info->tpmVendorID));
    }
    /* store vendorSpecificSize */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->vendorSpecificSize);
    }
    /* store vendorSpecific */
    if (rc == 0) {
	rc = TPM_Sbuffer_Append(sbuffer,
				tpm_cap_version_info->vendorSpecific,
				tpm_cap_version_info->vendorSpecificSize);
    }
    return rc;
}

/* TPM_CapVersionInfo_Delete()

   No-OP if the parameter is NULL, else:
   frees memory allocated for the object
   sets pointers to NULL
   calls TPM_CapVersionInfo_Init to set members back to default values
   The object itself is not freed
*/   

void TPM_CapVersionInfo_Delete(TPM_CAP_VERSION_INFO *tpm_cap_version_info)
{
    printf(" TPM_CapVersionInfo_Delete:\n");
    if (tpm_cap_version_info != NULL) {
	free(tpm_cap_version_info->vendorSpecific);
	TPM_CapVersionInfo_Init(tpm_cap_version_info);
    }
    return;
}

/*
  Processing Commands
*/


/* 17. Ordinals rev 107

   This structure maps the specification Ordinals table to software functions and parameters.

   It provides direct mapping that easier to understand and maintain than scattering and hard coding
   these values.

   The functions currently supported are:

	- processing jump table for 1.1 and 1.2 (implied get capability - ordinals supported)
	- allow audit
	- audit default value
	- owner delegation permissions
	- key delegation permissions
	- wrappable

   Future possibilities include:

	- no owner, disabled, deactivated
	- 0,1,2 auth

   typedef struct tdTPM_ORDINAL_TABLE {

   TPM_COMMAND_CODE ordinal;
   tpm_process_function_t process_function_v11;
   tpm_process_function_t process_function_v12;
   TPM_BOOL auditable;				       
   TPM_BOOL auditDefault;			       
   uint16_t ownerPermissionBlock;			
   uint32_t ownerPermissionPosition;			
   uint16_t keyPermissionBlock;			
   uint32_t keyPermissionPosition;
   uint32_t inputHandleSize;
   uint32_t keyHandles;
   uint32_t outputHandleSize;
   TPM_BOOL transportWrappable;
   TPM_BOOL instanceWrappable;				
   TPM_BOOL hardwareWrappable;
   } TPM_ORDINAL_TABLE;
*/

static TPM_ORDINAL_TABLE tpm_ordinal_table[] =
{
    {TPM_ORD_ActivateIdentity,
     TPM_Process_ActivateIdentity, TPM_Process_ActivateIdentity,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_ActivateIdentity,
     1, TPM_KEY_DELEGATE_ActivateIdentity,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_AuthorizeMigrationKey,
     TPM_Process_AuthorizeMigrationKey, TPM_Process_AuthorizeMigrationKey,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_AuthorizeMigrationKey,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CertifyKey,
     TPM_Process_CertifyKey, TPM_Process_CertifyKey,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_CertifyKey,
     sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE),
     2,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CertifyKey2,
     TPM_Process_Unused, TPM_Process_CertifyKey2,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_CertifyKey2,
     sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE),
     2,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CertifySelfTest,
     TPM_Process_CertifySelfTest, TPM_Process_Unused,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ChangeAuth,
     TPM_Process_ChangeAuth, TPM_Process_ChangeAuth,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_ChangeAuth,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ChangeAuthAsymFinish,
     TPM_Process_ChangeAuthAsymFinish, TPM_Process_ChangeAuthAsymFinish,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_ChangeAuthAsymFinish,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ChangeAuthAsymStart,
     TPM_Process_ChangeAuthAsymStart, TPM_Process_ChangeAuthAsymStart,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_ChangeAuthAsymStart,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ChangeAuthOwner,
     TPM_Process_ChangeAuthOwner, TPM_Process_ChangeAuthOwner,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_ApproveMA,
     TPM_Process_Unused, TPM_Process_CMK_ApproveMA,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_CMK_ApproveMA,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_ConvertMigration,
     TPM_Process_Unused, TPM_Process_CMK_ConvertMigration,
     TRUE,
     FALSE,
     1, TPM_KEY_DELEGATE_CMK_ConvertMigration,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_CreateBlob,
     TPM_Process_Unused, TPM_Process_CMK_CreateBlob,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_CMK_CreateBlob,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_CreateKey,
     TPM_Process_Unused, TPM_Process_CMK_CreateKey,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_CMK_CreateKey,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_CreateTicket,
     TPM_Process_Unused, TPM_Process_CMK_CreateTicket,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_CMK_CreateTicket,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CMK_SetRestrictions,
     TPM_Process_Unused, TPM_Process_CMK_SetRestrictions,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ContinueSelfTest,
     TPM_Process_ContinueSelfTest, TPM_Process_ContinueSelfTest,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ConvertMigrationBlob,
     TPM_Process_ConvertMigrationBlob, TPM_Process_ConvertMigrationBlob,
     TRUE,
     TRUE,
     0, 0,
     1, TPM_KEY_DELEGATE_ConvertMigrationBlob,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CreateCounter,
     TPM_Process_Unused, TPM_Process_CreateCounter,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_CreateCounter,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CreateEndorsementKeyPair,
     TPM_Process_CreateEndorsementKeyPair, TPM_Process_CreateEndorsementKeyPair,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_CreateMaintenanceArchive,
#ifdef TPM_NOMAINTENANCE
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
#else
     TPM_Process_CreateMaintenanceArchive, TPM_Process_CreateMaintenanceArchive,
     TRUE,
     TRUE,
#endif
     1, TPM_DELEGATE_CreateMaintenanceArchive,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CreateMigrationBlob,
     TPM_Process_CreateMigrationBlob, TPM_Process_CreateMigrationBlob,
     TRUE,
     TRUE,
     0, 0,
     1, TPM_KEY_DELEGATE_CreateMigrationBlob,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CreateRevocableEK,
     TPM_Process_Unused, TPM_Process_CreateRevocableEK,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_CreateWrapKey,
     TPM_Process_CreateWrapKey, TPM_Process_CreateWrapKey,
     TRUE,
     TRUE,
     0, 0,
     1, TPM_KEY_DELEGATE_CreateWrapKey,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DAA_Join,
     TPM_Process_Unused, TPM_Process_DAAJoin,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_DAA_Join,
     0, 0,
     sizeof(TPM_HANDLE),
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DAA_Sign,
     TPM_Process_Unused, TPM_Process_DAASign,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_DAA_Sign,
     0, 0,
     sizeof(TPM_HANDLE),
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_CreateKeyDelegation,
     TPM_Process_Unused, TPM_Process_DelegateCreateKeyDelegation,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_CreateOwnerDelegation,
     TPM_Process_Unused, TPM_Process_DelegateCreateOwnerDelegation,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_Delegate_CreateOwnerDelegation,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_LoadOwnerDelegation,
     TPM_Process_Unused, TPM_Process_DelegateLoadOwnerDelegation,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_Delegate_LoadOwnerDelegation,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_Manage,
     TPM_Process_Unused, TPM_Process_DelegateManage,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_Delegate_Manage,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_ReadTable,
     TPM_Process_Unused, TPM_Process_DelegateReadTable,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_UpdateVerification,
     TPM_Process_Unused, TPM_Process_DelegateUpdateVerification,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_Delegate_UpdateVerification,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Delegate_VerifyDelegation,
     TPM_Process_Unused, TPM_Process_DelegateVerifyDelegation,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DirRead,
     TPM_Process_DirRead, TPM_Process_DirRead,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DirWriteAuth,
     TPM_Process_DirWriteAuth, TPM_Process_DirWriteAuth,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_DirWriteAuth,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DisableForceClear,
     TPM_Process_DisableForceClear, TPM_Process_DisableForceClear,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DisableOwnerClear,
     TPM_Process_DisableOwnerClear, TPM_Process_DisableOwnerClear,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_DisableOwnerClear,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DisablePubekRead,
     TPM_Process_DisablePubekRead, TPM_Process_DisablePubekRead,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_DisablePubekRead,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_DSAP,
     TPM_Process_Unused, TPM_Process_DSAP,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_ENTITY_TYPE) + sizeof(TPM_KEY_HANDLE) + TPM_NONCE_SIZE + sizeof(uint32_t),
     0xffffffff,
     sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE,
     TRUE,
     TRUE,
     TRUE},
    
    {TPM_ORD_EstablishTransport,
     TPM_Process_Unused, TPM_Process_EstablishTransport,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_EstablishTransport,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     FALSE,
     FALSE,
     FALSE},
    
    {TPM_ORD_EvictKey,
     TPM_Process_EvictKey, TPM_Process_EvictKey,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ExecuteTransport,
     TPM_Process_Unused, TPM_Process_ExecuteTransport,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     FALSE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Extend,
     TPM_Process_Extend, TPM_Process_Extend,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_FieldUpgrade,
     TPM_Process_Unused, TPM_Process_Unused,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_FieldUpgrade,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_FlushSpecific,
     TPM_Process_Unused, TPM_Process_FlushSpecific,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_HANDLE),
     0xffffffff,
     0,
     TRUE,
     TRUE,
     TRUE},
    
    {TPM_ORD_ForceClear,
     TPM_Process_ForceClear, TPM_Process_ForceClear,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetAuditDigest,
     TPM_Process_Unused, TPM_Process_GetAuditDigest,
     FALSE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetAuditDigestSigned,
     TPM_Process_Unused, TPM_Process_GetAuditDigestSigned,
     FALSE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_GetAuditDigestSigned,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetAuditEvent,
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetAuditEventSigned,
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetCapability,
     TPM_Process_GetCapability, TPM_Process_GetCapability,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_GetCapabilityOwner,
     TPM_Process_GetCapabilityOwner, TPM_Process_GetCapabilityOwner,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetCapabilitySigned,
     TPM_Process_GetCapabilitySigned, TPM_Process_Unused,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetOrdinalAuditStatus,
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetPubKey,
     TPM_Process_GetPubKey, TPM_Process_GetPubKey,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_GetPubKey,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetRandom,
     TPM_Process_GetRandom, TPM_Process_GetRandom,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetTestResult,
     TPM_Process_GetTestResult, TPM_Process_GetTestResult,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_GetTicks,
     TPM_Process_Unused, TPM_Process_GetTicks,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_IncrementCounter,
     TPM_Process_Unused, TPM_Process_IncrementCounter,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Init,
     TPM_Process_Init, TPM_Process_Init,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_KeyControlOwner,
     TPM_Process_Unused, TPM_Process_KeyControlOwner,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_KeyControlOwner,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_KillMaintenanceFeature,
#ifdef TPM_NOMAINTENANCE
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
#else
     TPM_Process_KillMaintenanceFeature, TPM_Process_KillMaintenanceFeature,
     TRUE,
     TRUE,
#endif
     1, TPM_DELEGATE_KillMaintenanceFeature,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadAuthContext,
     TPM_Process_LoadAuthContext, TPM_Process_LoadAuthContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     sizeof(TPM_HANDLE),
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadContext,
     TPM_Process_Unused, TPM_Process_LoadContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_HANDLE),
     0,
     sizeof(TPM_HANDLE),
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_LoadKey,
     TPM_Process_LoadKey, TPM_Process_LoadKey,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_LoadKey,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadKey2,
     TPM_Process_Unused, TPM_Process_LoadKey2,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_LoadKey2,
     sizeof(TPM_KEY_HANDLE),
     1,
     sizeof(TPM_KEY_HANDLE),
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadKeyContext,
     TPM_Process_LoadKeyContext, TPM_Process_LoadKeyContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     sizeof(TPM_KEY_HANDLE),
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadMaintenanceArchive,
#ifdef TPM_NOMAINTENANCE
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
#else
     TPM_Process_LoadMaintenanceArchive, TPM_Process_LoadMaintenanceArchive,
     TRUE,
     TRUE,
#endif
     1, TPM_DELEGATE_LoadMaintenanceArchive,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_LoadManuMaintPub,
#ifdef TPM_NOMAINTENANCE
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
#else
     TPM_Process_LoadManuMaintPub, TPM_Process_LoadManuMaintPub,
     TRUE,
     TRUE,
#endif
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_MakeIdentity,
     TPM_Process_MakeIdentity, TPM_Process_MakeIdentity,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_MakeIdentity,
     1, TPM_KEY_DELEGATE_MakeIdentity,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_MigrateKey,
     TPM_Process_Unused, TPM_Process_MigrateKey,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_MigrateKey,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_NV_DefineSpace,
     TPM_Process_Unused, TPM_Process_NVDefineSpace,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_NV_DefineSpace,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_NV_ReadValue,
     TPM_Process_Unused, TPM_Process_NVReadValue,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_NV_ReadValue,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_NV_ReadValueAuth,
     TPM_Process_Unused, TPM_Process_NVReadValueAuth,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_NV_WriteValue,
     TPM_Process_Unused, TPM_Process_NVWriteValue,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_NV_WriteValue,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_NV_WriteValueAuth,
     TPM_Process_Unused, TPM_Process_NVWriteValueAuth,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_OIAP,
     TPM_Process_OIAP, TPM_Process_OIAP,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE,
     TRUE,
     TRUE,
     TRUE},
    
    {TPM_ORD_OSAP,
     TPM_Process_OSAP, TPM_Process_OSAP,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_ENTITY_TYPE) + sizeof(uint32_t) + TPM_NONCE_SIZE,
     0,		/* TPM_OSAP: no input or output parameters are encrypted or logged */
     sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE,
     TRUE,
     TRUE,
     TRUE},
    
    {TPM_ORD_OwnerClear,
     TPM_Process_OwnerClear, TPM_Process_OwnerClear,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_OwnerClear,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_OwnerReadInternalPub,
     TPM_Process_Unused, TPM_Process_OwnerReadInternalPub,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_OwnerReadInternalPub,
     0, 0,
     0,
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_OwnerReadPubek,
     TPM_Process_OwnerReadPubek, TPM_Process_OwnerReadPubek,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_OwnerReadPubek,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_OwnerSetDisable,
     TPM_Process_OwnerSetDisable, TPM_Process_OwnerSetDisable,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_OwnerSetDisable,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_PCR_Reset,
     TPM_Process_Unused, TPM_Process_PcrReset,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_PcrRead,
     TPM_Process_PcrRead, TPM_Process_PcrRead,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_PhysicalDisable,
     TPM_Process_PhysicalDisable, TPM_Process_PhysicalDisable,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_PhysicalEnable,
     TPM_Process_PhysicalEnable, TPM_Process_PhysicalEnable,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_PhysicalSetDeactivated,
     TPM_Process_PhysicalSetDeactivated, TPM_Process_PhysicalSetDeactivated,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_Quote,
     TPM_Process_Quote, TPM_Process_Quote,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Quote,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     TRUE},
    
    {TPM_ORD_Quote2,
     TPM_Process_Unused, TPM_Process_Quote2,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Quote2,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     TRUE},
    
    {TPM_ORD_ReadCounter,
     TPM_Process_Unused, TPM_Process_ReadCounter,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ReadManuMaintPub,
#ifdef TPM_NOMAINTENANCE
     TPM_Process_Unused, TPM_Process_Unused,
     FALSE,
     FALSE,
#else
     TPM_Process_ReadManuMaintPub, TPM_Process_ReadManuMaintPub,
     TRUE,
     TRUE,
#endif
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ReadPubek,
     TPM_Process_ReadPubek, TPM_Process_ReadPubek,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ReleaseCounter,
     TPM_Process_Unused, TPM_Process_ReleaseCounter,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ReleaseCounterOwner,
     TPM_Process_Unused, TPM_Process_ReleaseCounterOwner,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_ReleaseCounterOwner,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ReleaseTransportSigned,
     TPM_Process_Unused, TPM_Process_ReleaseTransportSigned,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_ReleaseTransportSigned,
     0,
     0,
     0,
     FALSE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Reset,
     TPM_Process_Reset, TPM_Process_Reset,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_ResetLockValue,
     TPM_Process_Unused, TPM_Process_ResetLockValue,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_ResetLockValue,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_RevokeTrust,
     TPM_Process_Unused, TPM_Process_RevokeTrust,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SaveAuthContext,
     TPM_Process_SaveAuthContext, TPM_Process_SaveAuthContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_AUTHHANDLE),
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SaveContext,
     TPM_Process_Unused, TPM_Process_SaveContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_HANDLE),
     0xffffffff,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_SaveKeyContext,
     TPM_Process_SaveKeyContext, TPM_Process_SaveKeyContext,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SaveState,
     TPM_Process_SaveState, TPM_Process_SaveState,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_Seal,
     TPM_Process_Seal, TPM_Process_Seal,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Seal,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Sealx,
     TPM_Process_Unused, TPM_Process_Sealx,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Sealx,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SelfTestFull,
     TPM_Process_SelfTestFull, TPM_Process_SelfTestFull,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetCapability,
     TPM_Process_Unused, TPM_Process_SetCapability,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_SetCapability,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_SetOperatorAuth,
     TPM_Process_Unused, TPM_Process_SetOperatorAuth,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetOrdinalAuditStatus,
     TPM_Process_SetOrdinalAuditStatus, TPM_Process_SetOrdinalAuditStatus,
     TRUE,
     TRUE,
     1, TPM_DELEGATE_SetOrdinalAuditStatus,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetOwnerInstall,
     TPM_Process_SetOwnerInstall, TPM_Process_SetOwnerInstall,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetOwnerPointer,
     TPM_Process_Unused, TPM_Process_SetOwnerPointer,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetRedirection,
     TPM_Process_Unused, TPM_Process_Unused,
     TRUE,
     FALSE,
     1, TPM_DELEGATE_SetRedirection,
     0, 0,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SetTempDeactivated,
     TPM_Process_SetTempDeactivated, TPM_Process_SetTempDeactivated,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SHA1Complete,
     TPM_Process_SHA1Complete, TPM_Process_SHA1Complete,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SHA1CompleteExtend,
     TPM_Process_SHA1CompleteExtend, TPM_Process_SHA1CompleteExtend,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SHA1Start,
     TPM_Process_SHA1Start, TPM_Process_SHA1Start,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_SHA1Update,
     TPM_Process_SHA1Update, TPM_Process_SHA1Update,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Sign,
     TPM_Process_Sign, TPM_Process_Sign,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Sign,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Startup,
     TPM_Process_Startup, TPM_Process_Startup,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TPM_ORD_StirRandom,
     TPM_Process_StirRandom, TPM_Process_StirRandom,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_TakeOwnership,
     TPM_Process_TakeOwnership, TPM_Process_TakeOwnership,
     TRUE,
     TRUE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Terminate_Handle,
     TPM_Process_TerminateHandle, TPM_Process_TerminateHandle,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     sizeof(TPM_AUTHHANDLE),
     0,
     0,
     TRUE,
     TRUE,
     TRUE},
    
    {TPM_ORD_TickStampBlob,
     TPM_Process_Unused, TPM_Process_TickStampBlob,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_TickStampBlob,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_UnBind,
     TPM_Process_UnBind, TPM_Process_UnBind,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_UnBind,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TPM_ORD_Unseal,
     TPM_Process_Unseal, TPM_Process_Unseal,
     TRUE,
     FALSE,
     0, 0,
     1, TPM_KEY_DELEGATE_Unseal,
     sizeof(TPM_KEY_HANDLE),
     1,
     0,
     TRUE,
     FALSE,
     FALSE},
    
    {TSC_ORD_PhysicalPresence,
     TPM_Process_PhysicalPresence, TPM_Process_PhysicalPresence,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     TRUE,
     FALSE},
    
    {TSC_ORD_ResetEstablishmentBit,
     TPM_Process_Unused, TPM_Process_ResetEstablishmentBit,
     TRUE,
     FALSE,
     0, 0,
     0, 0,
     0,
     0,
     0,
     TRUE,
     FALSE,
     FALSE}
    

    
};

/* 
   Ordinal Table Utilities
*/

/* TPM_OrdinalTable_GetEntry() gets the table entry for the ordinal.

   If the ordinal is not in the table, TPM_BAD_ORDINAL is returned
*/

TPM_RESULT TPM_OrdinalTable_GetEntry(TPM_ORDINAL_TABLE **entry,
				     TPM_ORDINAL_TABLE *ordinalTable,
				     TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT	rc = TPM_BAD_ORDINAL;
    size_t	i;

    /* printf(" TPM_OrdinalTable_GetEntry: Ordinal %08x\n", ordinal); */
    *entry = NULL;
    for (i = 0 ; i < (sizeof(tpm_ordinal_table)/sizeof(TPM_ORDINAL_TABLE)) ; i++) {
	if (ordinalTable[i].ordinal == ordinal) {	/* if found */
	    *entry = &(ordinalTable[i]);		/* return the entry */
	    rc = 0;					/* return found */
	    break;
	}
    }
    return rc;
}

/* TPM_OrdinalTable_GetProcessFunction() returns the processing function for the ordinal.

   If the ordinal is not in the table, the function TPM_Process_Unused() is returned.
*/

void TPM_OrdinalTable_GetProcessFunction(tpm_process_function_t *tpm_process_function,
					 TPM_ORDINAL_TABLE *ordinalTable,
					 TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT	rc = 0;
    TPM_ORDINAL_TABLE *entry;
    
    printf(" TPM_OrdinalTable_GetProcessFunction: Ordinal %08x\n", ordinal);

    if (rc == 0) {
	rc = TPM_OrdinalTable_GetEntry(&entry, ordinalTable, ordinal);
    }
    if (rc == 0) {	/* if found */
#ifdef TPM_V12
	*tpm_process_function = entry->process_function_v12;
#else
	*tpm_process_function = entry->process_function_v11;
#endif
    }
    else {	/* if not found, default processing function */
	*tpm_process_function = TPM_Process_Unused;
    }
    return;
}

/* TPM_OrdinalTable_GetAuditable() determines whether the ordinal can ever be audited.

   Used by TPM_Process_SetOrdinalAuditStatus()
*/

void TPM_OrdinalTable_GetAuditable(TPM_BOOL *auditable,
				   TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT	rc = 0;
    TPM_ORDINAL_TABLE *entry;
    
    printf(" TPM_OrdinalTable_GetAuditable: Ordinal %08x\n", ordinal);
    if (rc == 0) {
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal);
    }
    /* if not found, unimplemented, not auditable */
    if (rc != 0) {
	*auditable = FALSE;
    }
    /* if unimplemented, not auditable */
#ifdef TPM_V12
    else if (entry->process_function_v12 == TPM_Process_Unused) {
	*auditable = FALSE;
    }
#else
    else if (entry->process_function_v11 == TPM_Process_Unused) {
	*auditable = FALSE;
    }
#endif
    /* if found an entry, use it */
    else {
	*auditable = entry->auditable;
    }
    return;
}

/* TPM_OrdinalTable_GetAuditDefault() determines whether the ordinal is audited by default.

   Used to initialize TPM_PERMANENT_DATA -> ordinalAuditStatus

   Returns FALSE if the ordinal is not in the ordinals table.
*/

void TPM_OrdinalTable_GetAuditDefault(TPM_BOOL *auditDefault,
				      TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT rc = 0;
    TPM_ORDINAL_TABLE *entry;

    if (rc == 0) {
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal);
    }
    /* if not found, unimplemented, not auditable */
    if (rc != 0) {
	*auditDefault = FALSE;
    }
    /* found an entry, return it */
    else {
	*auditDefault = entry->auditDefault;
    }
    return;
}


/* TPM_OrdinalTable_GetOwnerPermission() gets the owner permission block and the position within the
   block for a permission bit based on the ordinal
*/

TPM_RESULT TPM_OrdinalTable_GetOwnerPermission(uint16_t *ownerPermissionBlock,
					       uint32_t *ownerPermissionPosition,
					       TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT rc = 0;
    TPM_ORDINAL_TABLE *entry;

    if (rc == 0) {
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal);
    }
    if (rc == 0) {
	*ownerPermissionBlock = entry->ownerPermissionBlock;
	*ownerPermissionPosition = entry->ownerPermissionPosition;
	/* sanity check ordinal table entry value */
	if (*ownerPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) {
	    printf("TPM_OrdinalTable_GetOwnerPermission: Error (fatal): "
		   "ownerPermissionPosition out of range %u\n", *ownerPermissionPosition);
	    rc = TPM_FAIL;	/* should never occur */
	}
    }
    return rc;
}

/* TPM_OrdinalTable_GetKeyPermission() gets the key permission block and the position within the
   block for a permission bit based on the ordinal
*/

TPM_RESULT TPM_OrdinalTable_GetKeyPermission(uint16_t *keyPermissionBlock,
					     uint32_t *keyPermissionPosition,
					     TPM_COMMAND_CODE ordinal)
{	
    TPM_RESULT rc = 0;
    TPM_ORDINAL_TABLE *entry;

    if (rc == 0) {
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal);
    }
    if (rc == 0) {
	*keyPermissionBlock = entry->keyPermissionBlock;
	*keyPermissionPosition = entry->keyPermissionPosition;
	if (*keyPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) {
	    printf("TPM_OrdinalTable_GetKeyPermission: Error (fatal): "
		   "keyPermissionPosition out of range %u\n", *keyPermissionPosition);
	    rc = TPM_FAIL;	/* should never occur */
	}
    }
    return rc;
}

/* TPM_OrdinalTable_ParseWrappedCmd() parses a transport wrapped command, extracting

	- index into DATAw
	- length of DATAw
	- number of key handles and their indexes
	- ordinal
	- transportWrappable FALSE if the command cannot be wrapped in a transport session

   FIXME if audit has to occur before command parsing, this command becomes more generally useful,
   and might do the auditing and return the inParamDigest as well.

   This function cannot get the actual key handle(s) because the value may be encrypted, and the
   decryption has not occurred yet.
*/

TPM_RESULT TPM_OrdinalTable_ParseWrappedCmd(uint32_t *datawStart,
					    uint32_t *datawLen,
					    uint32_t *keyHandles,
					    uint32_t *keyHandle1Index,
					    uint32_t *keyHandle2Index,
					    TPM_COMMAND_CODE *ordinal,
					    TPM_BOOL *transportWrappable,
					    TPM_SIZED_BUFFER *wrappedCmd)
{
    TPM_RESULT		rc = 0;
    uint32_t		stream_size;
    unsigned char	*stream;
    TPM_TAG		tag = 0;
    uint32_t		paramSize = 0;
    TPM_ORDINAL_TABLE	*entry;		/* table entry for the ordinal */
    uint32_t		authLen;	/* length of below the line parameters */

    printf(" TPM_OrdinalTable_ParseWrappedCmd:\n");
    /* Extract the standard command parameters from the command stream.	 This also validates
       paramSize against wrappedCmdSize */
    if (rc == 0) {
	/* make temporary copies so the wrappedCmd is not touched */
	/* FIXME might want to return paramSize and tag and move the wrappedCmd pointers */
	stream = wrappedCmd->buffer;
	stream_size = wrappedCmd->size;
	/* parse the three standard input parameters, check paramSize against wrappedCmd->size */
	rc = TPM_Process_GetCommandParams(&tag, &paramSize, ordinal,
					  &stream, &stream_size);
    }
    /* get the entry from the ordinal table */
    if (rc == 0) {
	printf("  TPM_OrdinalTable_ParseWrappedCmd: ordinal %08x\n", *ordinal);
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, *ordinal);
    }
    if (rc == 0) {
	/* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */
	*datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) +
		      entry->inputHandleSize;
	/* authLen is the length of the below-the-line auth parameters that are excluded from the
	   dataW area */
	switch (tag) {
	  case TPM_TAG_RQU_AUTH1_COMMAND:
	    authLen = sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE +
		      sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE;
	    break;
	  case TPM_TAG_RQU_AUTH2_COMMAND:
	    authLen = 2 *
		      (sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE +
		       sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE);
	    break;
	  case TPM_TAG_RQU_COMMAND:
	    /* if the tag is illegal, assume the dataW area goes to the end of the command */
	  default:
	    authLen = 0;
	    break;
	}
	if (paramSize < *datawStart + authLen) {
	    printf("TPM_OrdinalTable_ParseWrappedCmd: Error, "
		   "paramSize %u less than datawStart %u + authLen %u\n",
		   paramSize, *datawStart, authLen);
	    rc = TPM_BAD_PARAM_SIZE;
	}
    }
    if (rc == 0) {
	/* subtract safe, cannot be negative after above check */
	*datawLen = paramSize - *datawStart - authLen;
	printf("  TPM_OrdinalTable_ParseWrappedCmd: datawStart %u datawLen %u\n",
	       *datawStart, *datawLen);
	/* determine whether the command can be wrapped in a transport session */
	*transportWrappable = entry->transportWrappable;
	/* return the number of key handles */
	*keyHandles = entry->keyHandles;
    }
    if (rc == 0) {
	printf("  TPM_OrdinalTable_ParseWrappedCmd: key handles %u\n", *keyHandles);
	switch (*keyHandles) {
	  case 0:
	    /* no key handles */
	    break;
	  case 1:
	    /* one key handle */
	    *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE);
	    break;
	  case 2: 
	    /* first key handle */
	    *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE);
	    /* second key handle */
	    *keyHandle2Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) +
			       sizeof(TPM_KEY_HANDLE);
	    break;
	  case 0xffffffff:
	    printf("  TPM_OrdinalTable_ParseWrappedCmd: key handles special case\n");
	    /* potential key handle */
	    *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE);
	    /* can't determine handle type here since resourceType is encrypted */
	    break;
	  default:
	    /* sanity check ordinal table */
	    printf("TPM_OrdinalTable_ParseWrappedCmd: Error (fatal), "
		   "invalid key handles for %08x for ordinal %08x\n", *keyHandles, *ordinal);
	    rc = TPM_FAIL;	/* should never occur */
	    break;
	}
    }
    return rc;
}

/* TPM_OrdinalTable_ParseWrappedRsp() parses a transport wrapped response, extracting

   - index into DATAw
   - length of DATAw
   - return code RCw

   FIXME this command might do the auditing and return the outParamDigest as well.
*/

TPM_RESULT TPM_OrdinalTable_ParseWrappedRsp(uint32_t *datawStart,
					    uint32_t *datawLen,
					    TPM_RESULT *rcw,
					    TPM_COMMAND_CODE ordinal,
					    const unsigned char *wrappedRspStream,
					    uint32_t wrappedRspStreamSize)
{
    TPM_RESULT		rc = 0;
    TPM_TAG		tag = 0;
    uint32_t		paramSize = 0;
    TPM_ORDINAL_TABLE	*entry;		/* table entry for the ordinal */
    uint32_t		authLen;	/* length of below the line parameters */

    printf(" TPM_OrdinalTable_ParseWrappedRsp: ordinal %08x\n", ordinal);
    /* Extract the standard response parameters from the response stream.  This also validates
       paramSize against wrappedRspSize */
    if (rc == 0) {
	rc = TPM_Process_GetResponseParams(&tag, &paramSize, rcw,
					   (unsigned char **)&wrappedRspStream,
					   &wrappedRspStreamSize);
    }
    /* get the entry from the ordinal table */
    if (rc == 0) {
	printf(" TPM_OrdinalTable_ParseWrappedRsp: returnCode %08x\n", *rcw);
	rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal);
    }
    /* parse the success return code case */
    if ((rc == 0) && (*rcw == TPM_SUCCESS)) {
	if (rc == 0) {
	    /* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */
	    *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT) +
			  entry->outputHandleSize;
	    /* authLen is the length of the below-the-line auth parameters that are excluded from
	       the dataW area */
	    switch (tag) {
	      case TPM_TAG_RSP_AUTH1_COMMAND:
		authLen = TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE;
		break;
	      case TPM_TAG_RSP_AUTH2_COMMAND:
		authLen = 2 * (TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE);
		break;
	      case TPM_TAG_RSP_COMMAND:
		/* if the tag is illegal, assume the dataW area goes to the end of the response */
	      default:
		authLen = 0;
		break;
	    }
	    if (paramSize < *datawStart + authLen) {
		printf("TPM_OrdinalTable_ParseWrappedRsp: Error, "
		       "paramSize %u less than datawStart %u + authLen %u\n",
		       paramSize, *datawStart, authLen);
		rc = TPM_BAD_PARAM_SIZE;	/* FIXME not clear what to do here */
	    }
	}
	if (rc == 0) {
	    /* subtract safe, cannot be negative after about check */
	    *datawLen = paramSize - *datawStart - authLen;
	    printf("  TPM_OrdinalTable_ParseWrappedRsp: datawStart %u datawLen %u\n",
		   *datawStart, *datawLen);
	}
    }
    /* if the wrapped command failed, datawStart is not used, and datawLen is 0 */
    else if ((rc == 0) && (*rcw != TPM_SUCCESS)) {
	*datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT);
	*datawLen = 0;
	printf("  TPM_OrdinalTable_ParseWrappedRsp: datawLen %u\n", *datawLen);
    }
    return rc;
}

void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries);

void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries)
{
    size_t i;
    for (i = 0 ; (i < 4) && (i < TPM_KEY_HANDLES) ; i++) {
	printf("TPM_KeyHandleEntries_Trace: %lu handle %08x tpm_key %p\n",
	       (unsigned long)i, tpm_key_handle_entries[i].handle, tpm_key_handle_entries[i].key);
    }
    return;
}

void TPM_State_Trace(tpm_state_t *tpm_state);

void TPM_State_Trace(tpm_state_t *tpm_state)
{
    printf("TPM_State_Trace: disable %u p_deactive %u v_deactive %u owned %u state %u\n",
	   tpm_state->tpm_permanent_flags.disable,
	   tpm_state->tpm_permanent_flags.deactivated,
	   tpm_state->tpm_stclear_flags.deactivated,
	   tpm_state->tpm_permanent_data.ownerInstalled,
	   tpm_state->testState);
    return;
}

/* TPM_ProcessA() is an alternate to TPM_Process() that uses standard C types.  It provides an entry
   point to the TPM without requiring the TPM_STORE_BUFFER class.

   The design pattern for the response is:

   - set '*response' to NULL at the first call

   - on subsequent calls, pass 'response' and 'response_total' back in.  Set 'response_size' back
     to 0.

   On input:
   
   '*response' - pointer to a buffer that was allocated (can be NULL)

   'response_size' - the number of valid bytes in buffer (ignored if buffer is NULL, can be 0,
   cannot be greater than total.  Set to zero, unless one wants the TPM_Process() function to append
   a response to some existing data.

   '*response_total' - the total number of allocated bytes (ignored if buffer is NULL)

   On output:

   '*response' - pointer to a buffer that was allocated or reallocated

   'response_size' - the number of valid bytes in buffer
   
   '*response_total' - the total number of allocated or reallocated bytes
*/

TPM_RESULT TPM_ProcessA(unsigned char **response,
			uint32_t *response_size,
			uint32_t *response_total,
			unsigned char *command,		/* complete command array */
			uint32_t command_size)		/* actual bytes in command */

{
    TPM_RESULT rc = 0;
    TPM_STORE_BUFFER responseSbuffer;

    /* set the sbuffer from the response parameters */
    if (rc == 0) {
	rc = TPM_Sbuffer_Set(&responseSbuffer,
			     *response,
			     *response_size,
			     *response_total);
    }
    if (rc == 0) {
	rc = TPM_Process(&responseSbuffer,
			 command,		/* complete command array */
			 command_size);		/* actual bytes in command */

    }
    /* get the response parameters from the sbuffer */
    if (rc == 0) {
	TPM_Sbuffer_GetAll(&responseSbuffer,
			   response,
			   response_size,
			   response_total);
    }
    return rc;
}

/* Process the command from the host to the TPM.

   'command_size' is the actual size of the command stream.

   Returns:
       0 on success

       non-zero on a fatal error preventing the command from being processed.  The response is
       invalid in this case.
*/

TPM_RESULT TPM_Process(TPM_STORE_BUFFER *response,
		       unsigned char *command,		/* complete command array */
		       uint32_t command_size)		/* actual bytes in command */
{
    TPM_RESULT		rc = 0;				/* fatal error, no response */
    TPM_RESULT		returnCode = TPM_SUCCESS;	/* fatal error in ordinal processing,
							   can be returned */
    TPM_TAG		tag = 0;
    uint32_t		paramSize = 0;
    TPM_COMMAND_CODE	ordinal = 0;
    tpm_process_function_t tpm_process_function = NULL;	/* based on ordinal */
    tpm_state_t		*targetInstance = NULL;		/* TPM global state */
    TPM_STORE_BUFFER	localBuffer;		/* for response if instance was not found */
    TPM_STORE_BUFFER	*sbuffer;		/* either localBuffer or the instance response
						   buffer */

    TPM_Sbuffer_Init(&localBuffer);	/* freed @1 */
    /* get the global TPM state */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	targetInstance = tpm_instances[0];
    }
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	/* clear the response form the previous ordinal, the response buffer is reused */
	TPM_Sbuffer_Clear(&(targetInstance->tpm_stclear_data.ordinalResponse));
	/* extract the standard command parameters from the command stream */
	returnCode = TPM_Process_GetCommandParams(&tag, &paramSize, &ordinal,
						  &command, &command_size);
    }	 
    /* preprocessing common to all ordinals */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_Process_Preprocess(targetInstance, ordinal, NULL);
    }
    /* NOTE Only for debugging */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries);
    }
    /* process the ordinal */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	/* get the processing function from the ordinal table */
	TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal);
	/* call the processing function to execute the command */
	returnCode = tpm_process_function(targetInstance,
					  &(targetInstance->tpm_stclear_data.ordinalResponse),
					  tag, command_size, ordinal, command,
					  NULL);	/* not from encrypted transport */
    }
    /* NOTE Only for debugging */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries);
    }
    /* NOTE Only for debugging */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	TPM_State_Trace(targetInstance);
    }
#ifdef TPM_VOLATILE_STORE
    /* save the volatile state after each command to handle fail-over restart */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_VolatileAll_NVStore(targetInstance);
    }
#endif	/* TPM_VOLATILE_STORE */
    /* If the ordinal processing function returned without a fatal error, append its ordinalResponse
       to the output response buffer */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_Sbuffer_AppendSBuffer(response,
					       &(targetInstance->tpm_stclear_data.ordinalResponse));
    }
    if ((rc == 0) && (returnCode != TPM_SUCCESS)) {
	/* gets here if:
	   
	   - there was an error before the ordinal was processed	
	   - the ordinal returned a fatal error
	   - an error occurred appending the ordinal response
	    
	   returnCode should be the response
	   errors here are fatal, can't create an error response
	*/
	/* if it failed after the target instance was found, use the instance's response buffer */
	if (targetInstance != NULL) {
	    sbuffer = &(targetInstance->tpm_stclear_data.ordinalResponse);
	}
	/* if it failed before even the target instance was found, use a local buffer */
	else {
	    sbuffer = &localBuffer;
	}
	if (rc == 0) {
	    /* it's not even known whether the initial response was stored, so just start
	       over */
	    TPM_Sbuffer_Clear(sbuffer);
	    /* store the tag, paramSize, and returnCode */
	    printf("TPM_Process: Ordinal returnCode %08x %u\n",
		   returnCode, returnCode);
	    rc = TPM_Sbuffer_StoreInitialResponse(sbuffer, TPM_TAG_RQU_COMMAND, returnCode);
	}
	/* call this to handle the TPM_FAIL causing the TPM going into failure mode */
	if (rc == 0) {
	    rc = TPM_Sbuffer_StoreFinalResponse(sbuffer, returnCode, targetInstance);
	}
	if (rc == 0) {
	    rc = TPM_Sbuffer_AppendSBuffer(response, sbuffer);
	}
    }
    /*
      cleanup
    */
    TPM_Sbuffer_Delete(&localBuffer);	/* @1 */
    return rc;
}

/* TPM_Process_Wrapped() is called recursively to process a wrapped command.

   'command_size' is the actual size of the command stream.

   'targetInstance' is an input indicating the TPM instance being called.

   'transportInternal' not NULL indicates that this function was called recursively from
   TPM_ExecuteTransport

   For wrapped commands, this function cannot trust that command_size and the incoming paramSize in
   the command stream are consistent.  Therefore, this function checks for consistency.

   The processor ensures that the response bytes are set according to the outgoing paramSize on
   return.

   Returns:
	0 on success

	non-zero on a fatal error preventing the command from being processed.	The response is
	invalid in this case.
*/

TPM_RESULT TPM_Process_Wrapped(TPM_STORE_BUFFER *response,
			       unsigned char *command,		/* complete command array */
			       uint32_t command_size,		/* actual bytes in command */
			       tpm_state_t *targetInstance,	/* global TPM state */
			       TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT		rc = 0;				/* fatal error, no response */
    TPM_RESULT		returnCode = TPM_SUCCESS;	/* non-fatal error, returned in response */
    TPM_TAG		tag = 0;
    uint32_t		paramSize = 0;
    TPM_COMMAND_CODE	ordinal = 0;
    tpm_process_function_t tpm_process_function = NULL; /* based on ordinal */
    TPM_STORE_BUFFER	ordinalResponse;		/* response for this ordinal */
    
    printf("TPM_Process_Wrapped:\n");
    TPM_Sbuffer_Init(&ordinalResponse);		/* freed @1 */
    /* Set the tag, paramSize, and ordinal from the wrapped command stream */
    /* If paramSize does not equal the command stream size, return TPM_BAD_PARAM_SIZE */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_Process_GetCommandParams(&tag, &paramSize, &ordinal,
						  &command, &command_size);
    }
    /* preprocessing common to all ordinals */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_Process_Preprocess(targetInstance, ordinal, transportInternal);
    }
    /* process the ordinal */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	/* get the processing function from the ordinal table */
	TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal);
	/* call the processing function to execute the command */
	returnCode = tpm_process_function(targetInstance, &ordinalResponse,
					  tag, command_size, ordinal, command,
					  transportInternal);
    }
    /* If the ordinal processing function returned without a fatal error, append its ordinalResponse
       to the output response buffer */
    if ((rc == 0) && (returnCode == TPM_SUCCESS)) {
	returnCode = TPM_Sbuffer_AppendSBuffer(response, &ordinalResponse);
    }
    /* If:

       - an error in this function occurred before the ordinal was processed
       - the ordinal processing function returned a fatal error
       - an error occurred appending the ordinal response

       then use the return code of that failure as the final response.	Failure here is fatal, since
       no error code can be returned.
    */
    if ((rc == 0) && (returnCode != TPM_SUCCESS)) {
	rc = TPM_Sbuffer_StoreFinalResponse(response, returnCode, targetInstance);
    }
    /*
      cleanup
    */
    TPM_Sbuffer_Delete(&ordinalResponse);	/* @1 */
    return rc;
}

/* TPM_Process_GetCommandParams() gets the standard 3 parameters from the command input stream

   The stream is adjusted to point past the parameters.

   The resulting paramSize is checked against the stream size for consistency.	paramSize is
   returned for reference, but command_size reflects the remaining bytes in the stream.
*/

TPM_RESULT TPM_Process_GetCommandParams(TPM_TAG *tag,
					uint32_t *paramSize ,
					TPM_COMMAND_CODE *ordinal,
					unsigned char **command,
					uint32_t *command_size)
{
    TPM_RESULT	rc = 0;

    printf(" TPM_Process_GetCommandParams:\n");
    /* get tag */
    if (rc == 0) {
	rc = TPM_Load16(tag, command, command_size);
    }
    /* get paramSize */
    if (rc == 0) {
	rc = TPM_Load32(paramSize, command, command_size);
    }
    /* get ordinal */
    if (rc == 0) {
	rc = TPM_Load32(ordinal, command, command_size);
    }
    /* check the paramSize against the command_size */
    if (rc == 0) {
	if (*paramSize !=
	    *command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)) {

	    printf("TPM_Process_GetCommandParams: Error, "
		   "command size %lu not equal to paramSize %u\n",
		   (unsigned long)
		   (*command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)),
		   *paramSize);
	    rc = TPM_BAD_PARAM_SIZE;
	}
	else {
	    printf("  TPM_Process_GetCommandParams: tag %04x paramSize %u ordinal %08x\n",
		   *tag, *paramSize, *ordinal);
	}
    }
    return rc;
}

/* TPM_Process_GetResponseParams() gets the standard 3 parameters from the response output stream

   The stream is adjusted to point past the parameters.

   The resulting paramSize is checked against the stream size for consistency.	paramSize is
   returned for reference, but response_size reflects the remaining bytes in the stream.
*/

TPM_RESULT TPM_Process_GetResponseParams(TPM_TAG *tag,
					 uint32_t *paramSize ,
					 TPM_RESULT *returnCode,
					 unsigned char **response,
					 uint32_t *response_size)
{
    TPM_RESULT	rc = 0;

    printf(" TPM_Process_GetResponseParams:\n");
    /* get tag */
    if (rc == 0) {
	rc = TPM_Load16(tag, response, response_size);
    }
    /* get paramSize */
    if (rc == 0) {
	rc = TPM_Load32(paramSize, response, response_size);
    }
    /* get returnCode */
    if (rc == 0) {
	rc = TPM_Load32(returnCode, response, response_size);
    }
    /* check the paramSize against the response_size */
    if (rc == 0) {
	if (*paramSize != (*response_size + sizeof(TPM_TAG) +
			   sizeof(uint32_t) + sizeof(TPM_RESULT))) {
	    
	    printf("TPM_Process_GetResponseParams: Error, "
		   "response size %lu not equal to paramSize %u\n",
		   (unsigned long)
		   (*response_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)),
		   *paramSize);
	    rc = TPM_BAD_PARAM_SIZE;
	}
	else {
	    printf("  TPM_Process_GetResponseParams: tag %04x paramSize %u ordinal %08x\n",
		   *tag, *paramSize, *returnCode);
	}
    }
    return rc;
}

/* TPM_CheckRequestTagnnn() is common code to verify the command tag */

TPM_RESULT TPM_CheckRequestTag210(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;

    if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) &&
	(tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) &&
	(tpm_tag != TPM_TAG_RQU_COMMAND)) {
	printf("TPM_CheckRequestTag210: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_CheckRequestTag21(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;
    
    if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) &&
	(tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND)) {
	printf("TPM_CheckRequestTag21: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_CheckRequestTag2(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;
    
    if (tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) {
	printf("TPM_CheckRequestTag2: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_CheckRequestTag10(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;
    
    if ((tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) &&
	(tpm_tag != TPM_TAG_RQU_COMMAND)) {
	printf("TPM_CheckRequestTag10: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_CheckRequestTag1(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;
    
    if (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) {
	printf("TPM_CheckRequestTag1: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_CheckRequestTag0(TPM_TAG tpm_tag)
{
    TPM_RESULT	rc = 0;
    
    if (tpm_tag != TPM_TAG_RQU_COMMAND) {
	printf("TPM_CheckRequestTag0: Error, tag %04hx\n", tpm_tag);
	rc = TPM_BADTAG;
    }
    return rc;
}

TPM_RESULT TPM_Process_Unused(tpm_state_t *tpm_state,
			      TPM_STORE_BUFFER *response,
			      TPM_TAG tag,
			      uint32_t paramSize,
			      TPM_COMMAND_CODE ordinal,
			      unsigned char *command,
			      TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT	rcf = 0;

    printf("TPM_Process_Unused:\n");
    tpm_state = tpm_state;			/* not used */
    paramSize = paramSize;			/* not used */
    ordinal = ordinal;				/* not used */
    command = command;				/* not used */
    transportInternal = transportInternal;	/* not used */
    printf("TPM_Process_Unused: Ordinal returnCode %08x %u\n",
	   TPM_BAD_ORDINAL, TPM_BAD_ORDINAL);
    rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, TPM_BAD_ORDINAL);
    return rcf;
}

/* TPM_CheckState() should be called by all commands.  It checks a set of flags specified by
   tpm_check_map to determine whether the command can execute in that state.

   Returns: 0 if the command can execute
	    non-zero error code that should be returned as a response
*/

TPM_RESULT TPM_CheckState(tpm_state_t *tpm_state,
			  TPM_TAG tag,
			  uint32_t tpm_check_map)
{
    TPM_RESULT	rc = 0;

    printf(" TPM_CheckState: Check map %08x\n", tpm_check_map);
    /* check the dictionary attack lockout, only for authorized commands */
    if (rc == 0) {
	if ((tpm_check_map & TPM_CHECK_NO_LOCKOUT) && (tag != TPM_TAG_RQU_COMMAND)) {
	    rc = TPM_Authdata_CheckState(tpm_state);
	}
    }
    /* TPM_GetTestResult. This command can assist the TPM manufacturer in determining the cause of
       the self-test failure.  iii.  All other operations will return the error code
       TPM_FAILEDSELFTEST.  */
    if (rc == 0) {
	if (tpm_check_map & TPM_CHECK_NOT_SHUTDOWN) {
	    if (tpm_state->testState == TPM_TEST_STATE_FAILURE) {
		printf("TPM_CheckState: Error, shutdown is TRUE\n");
		rc = TPM_FAILEDSELFTEST;
	    }
	}
    }
    /* TPM_Startup SHALL execute as normal, and is the only function that does not call
       TPM_CheckState().  All other commands SHALL return TPM_INVALID_POSTINIT */
    if (rc == 0) {
	if (tpm_state->tpm_stany_flags.postInitialise) {
	    printf("TPM_CheckState: Error, postInitialise is TRUE\n");
	    rc = TPM_INVALID_POSTINIT;
	}
    }
    /*
      For checking disabled and deactivated, the check is NOT done if it's one of the special NV
      commands (indicated by TPM_CHECK_NV_NOAUTH) and nvLocked is FALSE, indicating that the NV
      store does not require authorization
    */
    /* For commands available only when enabled. */
    if (rc == 0) {
	if ((tpm_check_map & TPM_CHECK_ENABLED) &&
	    !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) {
	    if (tpm_state->tpm_permanent_flags.disable) {
		printf("TPM_CheckState: Error, disable is TRUE\n");
		rc = TPM_DISABLED;
	    }
	}
    }
    /* For commands only available when activated.  */
    if (rc == 0) {
	if ((tpm_check_map & TPM_CHECK_ACTIVATED) &&
	    !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) {
	    if (tpm_state->tpm_stclear_flags.deactivated) {
		printf("TPM_CheckState: Error, deactivated is TRUE\n");
		rc = TPM_DEACTIVATED;
	    }
	}
    }
    /* For commands available only after an owner is installed.	 see Ordinals chart */
    if (rc == 0) {
	if (tpm_check_map & TPM_CHECK_OWNER) {
	    if (!tpm_state->tpm_permanent_data.ownerInstalled) {
		printf("TPM_CheckState: Error, ownerInstalled is FALSE\n");
		rc = TPM_NOSRK;
	    }
	}
    }
    return rc;
}

/* TPM_Process_Preprocess() handles check functions common to all ordinals

   'transportPublic' not NULL indicates that this function was called recursively from
   TPM_ExecuteTransport
*/

TPM_RESULT TPM_Process_Preprocess(tpm_state_t *tpm_state,
				  TPM_COMMAND_CODE ordinal,
				  TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT		rc = 0;				/* fatal error, no response */

    printf(" TPM_Process_Preprocess: Ordinal %08x\n", ordinal);
    /* Preprocess to check if command can be run in limited operation mode */
    if (rc == 0) {
	if (tpm_state->testState == TPM_TEST_STATE_LIMITED) {
	    /* 1. At startup, a TPM MUST self-test all internal functions that are necessary to do
	       TPM_SHA1Start, TPM_SHA1Update, TPM_SHA1Complete, TPM_SHA1CompleteExtend, TPM_Extend,
	       TPM_Startup, TPM_ContinueSelfTest, a subset of TPM_GetCapability, and
	       TPM_GetTestResult..
	    */
	    if (!((ordinal == TPM_ORD_Startup) ||
		  (ordinal == TPM_ORD_SHA1Start) ||
		  (ordinal == TPM_ORD_SHA1Update) ||
		  (ordinal == TPM_ORD_SHA1Complete) ||
		  (ordinal == TPM_ORD_SHA1CompleteExtend) ||
		  (ordinal == TPM_ORD_Extend) ||
		  (ordinal == TPM_ORD_Startup) ||
		  (ordinal == TPM_ORD_ContinueSelfTest) ||
		  /* a subset of TPM_GetCapability does not require self-test.	The ordinal itself
		     decides whether to run TPM_ContinueSelfTest() */
		  (ordinal == TPM_ORD_GetCapability) ||
		  /* 3. The TPM MAY allow TPM_SelfTestFull to be used before completion of the
		     actions of TPM_ContinueSelfTest. */
		  (ordinal == TPM_ORD_SelfTestFull) ||
		  (ordinal == TPM_ORD_GetTestResult) ||
		  /* 2. The TSC_PhysicalPresence and TSC_ResetEstablishmentBit commands do not
		     operate on shielded-locations and have no requirement to be self-tested before
		     any use. TPM's SHOULD test these functions before operation. */
		  (ordinal == TSC_ORD_PhysicalPresence) ||
		  (ordinal == TSC_ORD_ResetEstablishmentBit)
		  )) {
		/* One of the optional actions. */
		/* rc = TPM_NEEDS_SELFTEST; */
		/* Alternatively, could run the actions of continue self-test */
		rc = TPM_ContinueSelfTestCmd(tpm_state);
	    }
	}
    }
    /* special pre-processing for SHA1 context */
    if (rc == 0) {
	rc = TPM_Check_SHA1Context(tpm_state, ordinal, transportInternal);
    }
    /* Special pre-processing to invalidate the saved state if it exists.  Omit this processing for
       TPM_Startup, since that function might restore the state first */
    if (rc == 0) {
	if (tpm_state->tpm_stany_flags.stateSaved &&
	    !((ordinal == TPM_ORD_Startup) ||
	      (ordinal == TPM_ORD_Init))) {
	    /* For any other ordinal, invalidate the saved state if it exists.	*/
	    rc = TPM_SaveState_NVDelete(tpm_state, TRUE);
	}
    }
    /* When an exclusive session is running, execution of any command other then
       TPM_ExecuteTransport or TPM_ReleaseTransportSigned targeting the exclusive session causes the
       abnormal invalidation of the exclusive transport session. */
    if ((rc == 0) && (transportInternal == NULL)) {	/* do test only for the outer ordinal */
	if ((tpm_state->tpm_stany_flags.transportExclusive != 0) &&	/* active exclusive */
	    /* These two ordinals terminate the exclusive transport session if the transport handle
	       is not the specified handle.  So the check is deferred until the command is parsed
	       for the transport handle. */
	    !((ordinal == TPM_ORD_ExecuteTransport) ||
	      (ordinal == TPM_ORD_ReleaseTransportSigned))) {
	    rc = TPM_TransportSessions_TerminateHandle
		 (tpm_state->tpm_stclear_data.transSessions,
		  tpm_state->tpm_stany_flags.transportExclusive,
		  &(tpm_state->tpm_stany_flags.transportExclusive));
	}
    }
    /* call platform specific code to set the localityModifier */
    if ((rc == 0) && (transportInternal == NULL)) {	/* do only for the outer ordinal */
	rc = TPM_IO_GetLocality(&(tpm_state->tpm_stany_flags.localityModifier),
				tpm_state->tpm_number);
    }
    return rc;
}


/* TPM_Check_SHA1Context() checks the current SHA1 context

   The TPM may not allow any other types of processing during the execution of a SHA-1
   session. There is only one SHA-1 session active on a TPM.  After the execution of SHA1Start, and
   prior to SHA1End, the receipt of any command other than SHA1Update will cause the invalidation of
   the SHA-1 session.

   2. After receipt of TPM_SHA1Start, and prior to the receipt of TPM_SHA1Complete or
   TPM_SHA1CompleteExtend, receipt of any command other than TPM_SHA1Update invalidates the SHA-1
   session.
   
   a. If the command received is TPM_ExecuteTransport, the SHA-1 session invalidation is based on
   the wrapped command, not the TPM_ExecuteTransport ordinal.
   
   b. A SHA-1 thread (start, update, complete) MUST take place either completely outside a transport
   session or completely within a single transport session.
*/

TPM_RESULT TPM_Check_SHA1Context(tpm_state_t *tpm_state,
				 TPM_COMMAND_CODE ordinal,
				 TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT rc = 0;

    if ((tpm_state->sha1_context != NULL) &&	/* if there was a SHA-1 context set up */
	(ordinal != TPM_ORD_ExecuteTransport))	/* depends on the wrapped command */
	{
	/* the non-SHA1 ordinals invalidate the SHA-1 session */
	if (
	    ((ordinal != TPM_ORD_SHA1Update) &&
	     (ordinal != TPM_ORD_SHA1Complete) &&
	     (ordinal != TPM_ORD_SHA1CompleteExtend)) ||
	    
	    /* invalidate if the SHA1 ordinal is within a transport session and the session was not
	       set up within the same transport session. */
	    ((transportInternal != NULL) &&
	     (tpm_state->transportHandle != transportInternal->transHandle)) ||

	    /* invalidate if the SHA1 ordinal is not within a transport session and the session was
	       set up with a transport session */
	    ((transportInternal == NULL) &&
	     (tpm_state->transportHandle != 0))
	    
	    ) {

	    printf("TPM_Check_SHA1Context: Invalidating SHA1 context\n");
	    TPM_SHA1Delete(&(tpm_state->sha1_context));
	}
    }
    return rc;
}

/* TPM_GetInParamDigest() does common processing of input parameters.
   
   Common processing includes:

   - determining if the ordinal is being run within an encrypted transport session, since the
     inParamDigest does not have to be calculated for audit in that case.

   - retrieving the audit status.  It is determinant of whether the input parameter digest should be
     calculated.

   - calculating the input parameter digest for HMAC authorization and/or auditing

   This function is called before authorization for several reasons.

   1 - It makes ordinal processing code more uniform, since authorization sometimes occurs far into
   the actions.

   2 - It is a minor optimization, since the resulting inParamDigest can be used twice in an auth-2
   command, as well as extending the audit digest.
*/
   
TPM_RESULT TPM_GetInParamDigest(TPM_DIGEST inParamDigest,		/* output */
				TPM_BOOL *auditStatus,			/* output */
				TPM_BOOL *transportEncrypt,		/* output */
				tpm_state_t *tpm_state,
				TPM_TAG tag,
				TPM_COMMAND_CODE ordinal,
				unsigned char *inParamStart,
				unsigned char *inParamEnd,
				TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT		rc = 0;			/* this function return code */ 
    TPM_COMMAND_CODE	nOrdinal;		/* ordinal in network byte order */
    
    printf(" TPM_GetInParamDigest:\n");
    if (rc == 0) {
	/* TRUE if called from encrypted transport session.  This is currently only needed when
	   auditing, but it's safer to always initialize it */
	*transportEncrypt = 
	    (transportInternal != NULL) &&	
	    (transportInternal->transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT);
	printf("  TPM_GetInParamDigest: transportEncrypt %02x\n", *transportEncrypt);
	/* Determine if the ordinal should be audited. */
	rc = TPM_OrdinalAuditStatus_GetAuditStatus(auditStatus,
						   ordinal,
						   &(tpm_state->tpm_permanent_data));
    }
    /* If inParamDigest is needed for:

       1 - for auditing (auditStatus == TRUE) and not called from an encrypted transport.  Different
       parameters are audited if the ordinal is called through an encrypted transport session.

       2 - for authorization (tag != auth-0)
    */
    if (rc == 0) {
	if ((*auditStatus && !(*transportEncrypt))	||	/* digest for auditing */
	    (tag != TPM_TAG_RQU_COMMAND)) {		/* digest for authorization */

	    /* convert ordinal to network byte order */
	    nOrdinal = htonl(ordinal);

	    /* a. Create inParamDigest - digest of inputs above the double line.  NOTE: If there
	       are no inputs other than the ordinal, inParamEnd - inParamStart will be 0,
	       terminating the SHA1 vararg hash.  It is important that the termination condition
	       be the length and not the NULL pointer. */
	    rc = TPM_SHA1(inParamDigest,
			  sizeof(TPM_COMMAND_CODE), &nOrdinal,	   /* 1S */
			  inParamEnd - inParamStart, inParamStart, /* 2S - ... */
			  0, NULL);
	    if (rc == 0) {
		TPM_PrintFour("  TPM_GetInParamDigest: inParamDigest", inParamDigest);
	    }
	}
    }
    return rc;
}

/* TPM_GetOutParamDigest() does common processing of output parameters.
   
   It calculates the output parameter digest for HMAC generation and/or auditing if required.	
*/	

TPM_RESULT TPM_GetOutParamDigest(TPM_DIGEST outParamDigest,	/* output */
				 TPM_BOOL auditStatus,		/* input audit status */
				 TPM_BOOL transportEncrypt,	/* wrapped in encrypt transport */
				 TPM_TAG tag,			
				 TPM_RESULT returnCode,
				 TPM_COMMAND_CODE ordinal,	/* command ordinal (hbo) */
				 unsigned char *outParamStart,	/* starting point of param's */
				 uint32_t outParamLength)	/* length of param's */
{
    TPM_RESULT		rc = 0; 
    TPM_RESULT		nreturnCode;	/* returnCode in nbo */
    TPM_COMMAND_CODE	nOrdinal;	/* ordinal in network byte order */
    
    printf(" TPM_GetOutParamDigest:\n");
    if (rc == 0)	{
	if ((auditStatus && !transportEncrypt) || (tag != TPM_TAG_RQU_COMMAND)) {
	    nreturnCode = htonl(returnCode);
	    nOrdinal = htonl(ordinal);	
	    /* a. Create outParamDigest - digest of outputs above the double line.  NOTE: If there
	       are no outputs other than the returnCode and ordinal, outParamLength
	       will be 0, terminating the SHA1 vararg hash.  It is important that the termination
	       condition be the length and not the NULL pointer. */
	    rc = TPM_SHA1(outParamDigest,
			  sizeof(TPM_RESULT), &nreturnCode,		/* 1S */
			  sizeof(TPM_COMMAND_CODE), &nOrdinal,		/* 2S */
			  outParamLength, outParamStart,		/* 3S - ...*/
			  0, NULL);
	    if (rc == 0) {
		TPM_PrintFour("  TPM_GetOutParamDigest: outParamDigest", outParamDigest);
	    }
	}	
    }	
    return rc;	
}	

/* TPM_ProcessAudit() rev 109

   This function is called when command auditing is required.
   
   This function must be called after the output authorization, since it requires the (almost) final
   return code.
*/
   
TPM_RESULT TPM_ProcessAudit(tpm_state_t *tpm_state,
			    TPM_BOOL transportEncrypt,	/* wrapped in encrypt transport */
			    TPM_DIGEST inParamDigest,
			    TPM_DIGEST outParamDigest,
			    TPM_COMMAND_CODE ordinal)
{
    TPM_RESULT		rc = 0;			/* audit return code */
    TPM_BOOL		isZero;
    TPM_RESULT		nreturnCode;		/* returnCode in nbo */
    TPM_COMMAND_CODE	nOrdinal;		/* ordinal in network byte order */
    TPM_DIGEST		transportDigest;	/* special case digest in encrypted transport */
    
    printf(" TPM_ProcessAudit:\n");

    /* The TPM will execute the ordinal and perform auditing in the following manner: */
    /* 1. Execute command */
    /* a. Execution implies the performance of the listed actions for the ordinal. */
    /* 2. If the command will return TPM_SUCCESS */
    /* a. If TPM_STANY_DATA -> auditDigest is all zeros */
    if (rc == 0) {
	TPM_Digest_IsZero(&isZero, tpm_state->tpm_stclear_data.auditDigest);
	if (isZero) {
	    /* i. Increment TPM_PERMANENT_DATA -> auditMonotonicCounter by 1 */
	    tpm_state->tpm_permanent_data.auditMonotonicCounter.counter++;
	    printf("  TPM_ProcessAudit: Incrementing auditMonotonicCounter to %u\n",
		   tpm_state->tpm_permanent_data.auditMonotonicCounter.counter);
	    rc = TPM_PermanentAll_NVStore(tpm_state,
					  TRUE,		/* write NV */
					  0);		/* no roll back */
	}
    }
    /* b. Create A1 a TPM_AUDIT_EVENT_IN structure */
    /* i. Set A1 -> inputParms to the digest of the input parameters from the command */
    /* (1) Digest value according to the HMAC digest rules of the "above the line" parameters
       (i.e. the first HMAC digest calculation). */
    /* ii. Set A1 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */
    /* c. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A1) */
    if (rc == 0) {
	/* normal case, audit uses inParamDigest */
	if (!transportEncrypt) {
	    rc = TPM_AuditDigest_ExtendIn(tpm_state, inParamDigest);
	}
	/* 1. When the wrapped command requires auditing and the transport session specifies
	   encryption, the TPM MUST perform the audit. However, when computing the audit digest:
	*/
	else {
	    /* a. For input, only the ordinal is audited. */
	    if (rc == 0) {
		nOrdinal = htonl(ordinal);
		rc = TPM_SHA1(transportDigest,
			      sizeof(TPM_COMMAND_CODE), &nOrdinal,
			      0, NULL);
	    }
	    if (rc == 0) {
		rc = TPM_AuditDigest_ExtendIn(tpm_state, transportDigest);
	    }
	}
    }
    /* d. Create A2 a TPM_AUDIT_EVENT_OUT structure */
    /* i. Set A2 -> outputParms to the digest of the output parameters from the command */
    /* (1). Digest value according to the HMAC digest rules of the "above the line" parameters
       (i.e. the first HMAC digest calculation). */
    /* ii. Set A2 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */
    /* e. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A2) */

    /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and
       the audit occurs before the state is saved.  If an error occurs while or after the state is
       saved, the audit still occurs.
    */
    if ((rc == 0) && (ordinal != TPM_ORD_SaveState)) {
	/* normal case, audit uses outParamDigest */
	if (!transportEncrypt) {
	    rc = TPM_AuditDigest_ExtendOut(tpm_state, outParamDigest);
	}
	/* 1. When the wrapped command requires auditing and the transport session specifies
	   encryption, the TPM MUST perform the audit. However, when computing the audit digest:
	*/
	else {
	    /* b. For output, only the ordinal and return code are audited. */
	    if (rc == 0) {
		nreturnCode = htonl(TPM_SUCCESS);	/* only called when TPM_SUCCESS */
		nOrdinal = htonl(ordinal);
		rc = TPM_SHA1(transportDigest,
			      sizeof(TPM_RESULT), &nreturnCode,
			      sizeof(TPM_COMMAND_CODE), &nOrdinal,
			      0, NULL);
	    }
	    if (rc == 0) {
		rc = TPM_AuditDigest_ExtendOut(tpm_state, transportDigest);
	    }
	}
    }
    /* 1. When, in performing the audit process, the TPM has an internal failure (unable to write,
       SHA-1 failure etc.) the TPM MUST set the internal TPM state such that the TPM returns the
       TPM_FAILEDSELFTEST error on subsequent attempts to execute a command. */
    /* 2. The return code for the command uses the following rules */
    /* a. Command result success, audit success -> return TPM_SUCCESS */
    /* b. Command result failure, no audit -> return command result failure */
    /* c. Command result success, audit failure -> return TPM_AUDITFAIL_SUCCESSFUL */
    /* 3. If the TPM is permanently nonrecoverable after an audit failure, then the TPM MUST always
       return TPM_FAILEDSELFTEST for every command other than TPM_GetTestResult.  This state must
       persist regardless of power cycling, the execution of TPM_Init or any other actions. */
    if (rc != 0) {
	rc = TPM_AUDITFAIL_SUCCESSFUL;
	tpm_state->testState = TPM_TEST_STATE_FAILURE;
    }
    return rc;
}

/*
  Processing Functions
*/

/* 7.1 TPM_GetCapability rev 99

   This command returns current information regarding the TPM.

   The limitation on what can be returned in failure mode restricts the information a manufacturer
   may return when capArea indicates TPM_CAP_MFR.
*/

TPM_RESULT TPM_Process_GetCapability(tpm_state_t *tpm_state,
				     TPM_STORE_BUFFER *response,
				     TPM_TAG tag,
				     uint32_t paramSize,
				     TPM_COMMAND_CODE ordinal,
				     unsigned char *command,
				     TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT	rcf = 0;		/* fatal error precluding response */
    TPM_TAG	returnCode = 0;		/* command return code */

    /* input parameters */
    TPM_CAPABILITY_AREA capArea;	/* Partition of capabilities to be interrogated */
    TPM_SIZED_BUFFER	subCap;		/* Further definition of information */

    /* processing parameters */
    unsigned char *	inParamStart;		/* starting point of inParam's */
    unsigned char *	inParamEnd;		/* ending point of inParam's */
    TPM_DIGEST		inParamDigest;
    TPM_BOOL		auditStatus;		/* audit the ordinal */
    TPM_BOOL		transportEncrypt;	/* wrapped in encrypted transport session */
    uint16_t		subCap16 = 0;		/* the subCap as a uint16_t */
    uint32_t		subCap32 = 0;		/* the subCap as a uint32_t */
    TPM_STORE_BUFFER	capabilityResponse;	/* response */

    /* output parameters */
    uint32_t		outParamStart;	/* starting point of outParam's */
    uint32_t		outParamEnd;	/* ending point of outParam's */
    TPM_DIGEST		outParamDigest;
    
    printf("TPM_Process_GetCapability: Ordinal Entry\n");
    TPM_SizedBuffer_Init(&subCap);		/* freed @1 */
    TPM_Sbuffer_Init(&capabilityResponse);	/* freed @2 */
    /*
      get inputs
    */
    /* save the starting point of inParam's for authorization and auditing */
    inParamStart = command;
    /* get capArea parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Load32(&capArea, &command, &paramSize);
    }
    /* get subCap parameter */
    if (returnCode == TPM_SUCCESS) {
	printf("TPM_Process_GetCapability: capArea %08x\n", capArea);
	returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
    }
    /* subCap is often a uint16_t or uint32_t, create them now */
    if (returnCode == TPM_SUCCESS) {
	TPM_GetSubCapInt(&subCap16, &subCap32, &subCap);
    }
    /* save the ending point of inParam's for authorization and auditing */
    inParamEnd = command;
    /* digest the input parameters */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_GetInParamDigest(inParamDigest,	/* output */
					  &auditStatus,		/* output */
					  &transportEncrypt,	/* output */
					  tpm_state,
					  tag,
					  ordinal,
					  inParamStart,
					  inParamEnd,
					  transportInternal);
    }
    /* check state */
    /* The shutdown test is delayed until after the subcap is calculated */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_NO_LOCKOUT);
    }
    /* check tag */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckRequestTag0(tag);
    }
    if (returnCode == TPM_SUCCESS) {
	if (paramSize != 0) {
	    printf("TPM_Process_GetCapability: Error, command has %u extra bytes\n",
		   paramSize);
	    returnCode = TPM_BAD_PARAM_SIZE;
	}
    }
    /*
      check state
    */
    /* 1. The TPM validates the capArea and subCap indicators. If the information is available, the
	  TPM creates the response field and fills in the actual information. */
    /* 2. The structure document contains the list of caparea and subCap values */
    if (returnCode == TPM_SUCCESS) {
	/* 3. If the TPM is in failure mode or limited operation mode, the TPM MUST return */
	if ((tpm_state->testState == TPM_TEST_STATE_FAILURE) ||
	    (tpm_state->testState == TPM_TEST_STATE_LIMITED)) {
	    /* a. TPM_CAP_VERSION */
	    /* b. TPM_CAP_VERSION_VAL */
	    /* c. TPM_CAP_MFR */
	    /* d. TPM_CAP_PROPERTY -> TPM_CAP_PROP_MANUFACTURER */
	    /* e. TPM_CAP_PROPERTY -> TPM_CAP_PROP_DURATION */
	    /* f. TPM_CAP_PROPERTY -> TPM_CAP_PROP_TIS_TIMEOUT */
	    /* g. The TPM MAY return any other capability. */
	    if (
		!(capArea == TPM_CAP_VERSION) &&
		!(capArea == TPM_CAP_VERSION_VAL) &&
		!(capArea == TPM_CAP_MFR) &&
		!((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_MANUFACTURER)) &&
		!((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_DURATION)) &&
		!((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_TIS_TIMEOUT))
		) {
		if (tpm_state->testState == TPM_TEST_STATE_FAILURE)  {
		    printf("TPM_Process_GetCapability: Error, shutdown capArea %08x subCap %08x\n",
			   capArea, subCap32);
		    returnCode = TPM_FAILEDSELFTEST;
		}
		else {
		    printf("TPM_Process_GetCapability: Limited operation, run self-test\n");
		    returnCode = TPM_ContinueSelfTestCmd(tpm_state);
		}
	    }
	}
    }
    /*
      Processing
    */
    if (returnCode == TPM_SUCCESS) {
	printf("TPM_Process_GetCapability: capArea %08x subCap32 subCap16 %08x %04x\n",
	       capArea, subCap32, subCap16);
	returnCode = TPM_GetCapabilityCommon(&capabilityResponse, tpm_state,
					     capArea, subCap16, subCap32, &subCap);
    }
    /*
      response
    */
    if (rcf == 0) {
	printf("TPM_Process_GetCapability: Ordinal returnCode %08x %u\n",
	       returnCode, returnCode);
	rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
    }
    if (rcf == 0) {
	if (returnCode == TPM_SUCCESS) {
	    /* checkpoint the beginning of the outParam's */
	    outParamStart = response->buffer_current - response->buffer;
	    /* store the capabilityResponse */
	    returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &capabilityResponse);
	    /* checkpoint the end of the outParam's */
	    outParamEnd = response->buffer_current - response->buffer;
	}
	/* digest the above the line output parameters */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_GetOutParamDigest(outParamDigest,	/* output */
					       auditStatus,	/* input audit status */
					       transportEncrypt,
					       tag,			
					       returnCode,
					       ordinal,		/* command ordinal */
					       response->buffer + outParamStart,	/* start */
					       outParamEnd - outParamStart);	/* length */
	}
	/* audit if required */
	if ((returnCode == TPM_SUCCESS) && auditStatus) {
	    returnCode = TPM_ProcessAudit(tpm_state,
					  transportEncrypt,
					  inParamDigest,
					  outParamDigest,
					  ordinal);
	}
	/* adjust the initial response */
	rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
    }
    /*
      cleanup
    */
    TPM_SizedBuffer_Delete(&subCap);		/* @1 */
    TPM_Sbuffer_Delete(&capabilityResponse);	/* @2 */
    return rcf;
}

/* TPM_GetSubCapInt() converts from a TPM_SIZED_BUFFER to either a uint16_t or uint32_t as
   applicable

   No return code is needed.  If the size it not applicable, a 0 value is returned, which is
   (fortunately) always illegal for subCap integral values.
*/

void TPM_GetSubCapInt(uint16_t *subCap16,
		      uint32_t *subCap32,
		      TPM_SIZED_BUFFER *subCap)
{
    *subCap16 = 0;	/* default, means was not a uint16_t */
    *subCap32 = 0;	/* default, means was not a uint32_t */
    if (subCap->size == sizeof(uint32_t)) {
	*subCap32 = htonl(*(uint32_t *)subCap->buffer);
	printf(" TPM_GetSubCapInt: subCap %08x\n", *subCap32);
    }
    else if (subCap->size == sizeof(uint16_t)) {
	*subCap16 = htons(*(uint16_t *)subCap->buffer);
	printf(" TPM_GetSubCapInt: subCap %04x\n", *subCap16);
    }
}


/* TPM_GetCapabilityCommon() is common code for getting a capability.
   
   It loads the result to 'capabilityResponse'

   A previously called TPM_GetSubCapInt() converts the subCap buffer into a subCap16 if the size is
   2 or subCap32 if the size is 4.  If the values are used, this function checks the size to ensure
   that the incoming subCap parameter was correct for the capArea.
*/

TPM_RESULT TPM_GetCapabilityCommon(TPM_STORE_BUFFER *capabilityResponse,
				   tpm_state_t *tpm_state, 
				   TPM_CAPABILITY_AREA capArea, 
				   uint16_t subCap16, 
				   uint32_t subCap32,
				   TPM_SIZED_BUFFER *subCap)
			     
{
    TPM_RESULT rc = 0;

    printf(" TPM_GetCapabilityCommon: capArea %08x\n", capArea);
    switch (capArea) {
      case TPM_CAP_ORD:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapOrd(capabilityResponse, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_ALG:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapAlg(capabilityResponse, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_PID:
	if (subCap->size == sizeof(uint16_t)) {
	    rc = TPM_GetCapability_CapPid(capabilityResponse, subCap16);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_FLAG: 
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapFlag(capabilityResponse, tpm_state, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_PROPERTY: 
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapProperty(capabilityResponse, tpm_state, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_VERSION: 
	rc = TPM_GetCapability_CapVersion(capabilityResponse);
	break;
      case TPM_CAP_KEY_HANDLE:
	/* This is command is available for backwards compatibility. It is the same as
	   TPM_CAP_HANDLE with a resource type of keys. */
	rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse,
					       tpm_state->tpm_key_handle_entries);
	break;
      case TPM_CAP_CHECK_LOADED: 
	rc = TPM_GetCapability_CapCheckLoaded(capabilityResponse,
					      tpm_state->tpm_key_handle_entries,
					      subCap);
	break;
      case TPM_CAP_SYM_MODE:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapSymMode(capabilityResponse, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_KEY_STATUS: 
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapKeyStatus(capabilityResponse,
						tpm_state->tpm_key_handle_entries,
						subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_NV_LIST:
	rc = TPM_NVIndexEntries_GetNVList(capabilityResponse, &(tpm_state->tpm_nv_index_entries));
	break;
      case TPM_CAP_MFR:
	rc = TPM_GetCapability_CapMfr(capabilityResponse, tpm_state, subCap);
	break;
      case TPM_CAP_NV_INDEX: 
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapNVIndex(capabilityResponse, tpm_state, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_TRANS_ALG:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapTransAlg(capabilityResponse, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_HANDLE:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapHandle(capabilityResponse, tpm_state, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_TRANS_ES:
	if (subCap->size == sizeof(uint16_t)) {
	    rc = TPM_GetCapability_CapTransEs(capabilityResponse, subCap16);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_AUTH_ENCRYPT:
	if (subCap->size == sizeof(uint32_t)) {
	    rc = TPM_GetCapability_CapAuthEncrypt(capabilityResponse, subCap32);
	}
	else {
	    printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size);
	    rc = TPM_BAD_MODE;
	}
	break;
      case TPM_CAP_SELECT_SIZE:
	rc = TPM_GetCapability_CapSelectSize(capabilityResponse, subCap);
	break;
#if  (TPM_REVISION >= 103)	/* added for rev 103 */
      case TPM_CAP_DA_LOGIC:
	rc = TPM_GetCapability_CapDaLogic(capabilityResponse, subCap, tpm_state);
	break;
#endif
      case TPM_CAP_VERSION_VAL:
	rc = TPM_GetCapability_CapVersionVal(capabilityResponse,
					     &(tpm_state->tpm_permanent_data));
	break;
      default:
	printf("TPM_GetCapabilityCommon: Error, unsupported capArea %08x", capArea);
	rc = TPM_BAD_MODE;
	break;
    }
    return rc;
}

/* Boolean value.

   TRUE indicates that the TPM supports the ordinal.

   FALSE indicates that the TPM does not support the ordinal.
*/

static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse,
					   uint32_t ordinal)
{
    TPM_RESULT			rc = 0;
    tpm_process_function_t	tpm_process_function;
    TPM_BOOL			supported;

    TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal);
    /* determine of the ordinal is supported */
    if (tpm_process_function != TPM_Process_Unused) {
	supported = TRUE;
    }
    /* if the processing function is 'Unused', it's not supported */
    else {
	supported = FALSE;
    }	
    printf("  TPM_GetCapability_CapOrd: Ordinal %08x, result %02x\n",
	   ordinal, supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}

/* algorithmID is TPM_ALG_XX: A value from TPM_ALGORITHM_ID

   Boolean value. TRUE means that the TPM supports the asymmetric algorithm for TPM_Sign, TPM_Seal,
   TPM_UnSeal and TPM_UnBind and related commands. FALSE indicates that the asymmetric algorithm is
   not supported for these types of commands. The TPM MAY return TRUE or FALSE for other than
   asymmetric algoroithms that it supports. Unassigned and unsupported algorithm IDs return FALSE.
*/

static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse,
					   uint32_t algorithmID)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	supported;

    printf(" TPM_GetCapability_CapAlg: algorithmID %08x\n", algorithmID);
    if (algorithmID == TPM_ALG_RSA) {
	supported = TRUE;
    }
    else {
	supported = FALSE;
    }
    printf("  TPM_GetCapability_CapAlg: Result %08x\n", supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}    

/* Boolean value.

   TRUE indicates that the TPM supports the protocol,

   FALSE indicates that the TPM does not support the protocol.
*/

static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse,
					   uint16_t protocolID)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	supported;

    printf(" TPM_GetCapability_CapPid: protocolID %04hx\n", protocolID);
    switch (protocolID) {
	/* supported protocols */
      case TPM_PID_OIAP:
      case TPM_PID_OSAP:
      case TPM_PID_ADIP:
      case TPM_PID_ADCP:
      case TPM_PID_DSAP:
      case TPM_PID_TRANSPORT:
      case TPM_PID_OWNER:
	supported = TRUE;
	break;
	/* unsupported protocols */
      default:
	supported = FALSE;
	break;
    }	
    printf("  TPM_GetCapability_CapPid: Result %08x\n", supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}    

/*
  Either of the next two subcaps

  TPM_CAP_FLAG_PERMANENT  Return the TPM_PERMANENT_FLAGS structure

  TPM_CAP_FLAG_VOLATILE	 Return the TPM_STCLEAR_FLAGS structure
*/

static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse,
					    tpm_state_t *tpm_state,
					    uint32_t capFlag)
{
    TPM_RESULT	rc = 0;

    printf(" TPM_GetCapability_CapFlag: capFlag %08x\n", capFlag);
    switch (capFlag) {
      case TPM_CAP_FLAG_PERMANENT:
	printf("  TPM_GetCapability_CapFlag: TPM_CAP_FLAG_PERMANENT\n");;
	rc = TPM_PermanentFlags_StoreBytes(capabilityResponse, &(tpm_state->tpm_permanent_flags));
	break;
      case TPM_CAP_FLAG_VOLATILE:
	printf("  TPM_GetCapability_CapFlag: TPM_CAP_FLAG_VOLATILE\n");
	rc = TPM_StclearFlags_Store(capabilityResponse, &(tpm_state->tpm_stclear_flags));
	break;
      default:
	printf("TPM_GetCapability_CapFlag: Error, illegal capFlag %08x\n", capFlag);
	rc = TPM_BAD_MODE;
	break;
    }
    return rc;
}    

/* TPM_GetCapability_CapProperty() handles Subcap values for CAP_PROPERTY rev 100
 */

static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse,
						tpm_state_t *tpm_state,
						uint32_t capProperty)
{
    TPM_RESULT	rc = 0;
    uint32_t 	uint32;
    uint32_t 	uint32a;
    uint32_t 	dummy;	/* to hold unused response parameter */

    printf(" TPM_GetCapability_CapProperty: capProperty %08x\n", capProperty);
    switch (capProperty) {
      case TPM_CAP_PROP_PCR:	/* Returns the number of PCR registers supported by the TPM */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_PCR %u\n", TPM_NUM_PCR);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_PCR);
	break;
      case TPM_CAP_PROP_DIR:	/* Returns the number of DIR registers under control of the TPM
				   owner supported by the TPM. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DIR %u\n", TPM_AUTHDIR_SIZE);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_AUTHDIR_SIZE);
	break;
      case TPM_CAP_PROP_MANUFACTURER:	/* Returns the Identifier of the TPM manufacturer. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MANUFACTURER %.4s\n",
	       TPM_MANUFACTURER);
	rc = TPM_Sbuffer_Append(capabilityResponse, (const unsigned char *)TPM_MANUFACTURER, 4);
	break;
      case TPM_CAP_PROP_KEYS:	/* Returns the number of 2048-bit RSA keys that can be loaded. This
				   MAY vary with time and circumstances. */
	TPM_KeyHandleEntries_GetSpace(&uint32, tpm_state->tpm_key_handle_entries);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_KEYS %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_MIN_COUNTER: /* uint32_t. The minimum amount of time in 10ths of a second
					that must pass between invocations of incrementing the
					monotonic counter. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MIN_COUNTER\n");
	rc = TPM_Sbuffer_Append32(capabilityResponse, 0);
	break;
      case TPM_CAP_PROP_AUTHSESS:	/* The number of available authorization sessions. This MAY
					   vary with time and circumstances. */
	TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_AUTHSESS space %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_TRANSESS:	/* The number of available transport sessions. This MAY vary
					   with time and circumstances.	 */
	TPM_TransportSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.transSessions);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TRANSESS space %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_COUNTERS:	/* The number of available monotonic counters. This MAY vary
					   with time and circumstances. */
	TPM_Counters_GetSpace(&uint32, tpm_state->tpm_permanent_data.monotonicCounter);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_COUNTERS %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_MAX_AUTHSESS:	/* The maximum number of loaded authorization sessions the
					   TPM supports. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_AUTHSESS %u\n",
	       TPM_MIN_AUTH_SESSIONS);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_AUTH_SESSIONS);
	break;
      case TPM_CAP_PROP_MAX_TRANSESS:	/* The maximum number of loaded transport sessions the TPM
					   supports. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_TRANSESS %u\n",
	       TPM_MIN_TRANS_SESSIONS);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_TRANS_SESSIONS);
	break;
      case TPM_CAP_PROP_MAX_COUNTERS:	/* The maximum number of monotonic counters under control of
					   TPM_CreateCounter */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_COUNTERS %u\n",
	       TPM_MIN_COUNTERS);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_COUNTERS);
	break;
      case TPM_CAP_PROP_MAX_KEYS:	/* The maximum number of 2048 RSA keys that the TPM can
					   support. The number does not include the EK or SRK. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_KEYS %u\n", TPM_KEY_HANDLES);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_KEY_HANDLES);
	break;
      case TPM_CAP_PROP_OWNER:	/* A value of TRUE indicates that the TPM has successfully installed
				   an owner. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_OWNER %02x\n",
	       tpm_state->tpm_permanent_data.ownerInstalled);
	rc = TPM_Sbuffer_Append(capabilityResponse,
				&(tpm_state->tpm_permanent_data.ownerInstalled), sizeof(TPM_BOOL));
	break;
      case TPM_CAP_PROP_CONTEXT:	/* The number of available saved session slots. This MAY
					   vary with time and circumstances. */
	TPM_ContextList_GetSpace(&uint32, &dummy, tpm_state->tpm_stclear_data.contextList);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_MAX_CONTEXT:	/* The maximum number of saved session slots. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_CONTEXT %u\n",
	       TPM_MIN_SESSION_LIST);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_SESSION_LIST);
	break;
      case TPM_CAP_PROP_FAMILYROWS:	/* The number of rows in the family table */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_FAMILYROWS %u\n",
	       TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
	break;
      case TPM_CAP_PROP_TIS_TIMEOUT:
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TIS_TIMEOUT\n");
	rc = TPM_GetCapability_CapPropTisTimeout(capabilityResponse);
	break;
      case TPM_CAP_PROP_STARTUP_EFFECT: /* The TPM_STARTUP_EFFECTS structure */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_STARTUP_EFFECT %08x\n",
	       TPM_STARTUP_EFFECTS_VALUE);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_STARTUP_EFFECTS_VALUE);
	break;
      case TPM_CAP_PROP_DELEGATE_ROW:	/* The size of the delegate table in rows. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DELEGATE_ENTRIES %u\n",
	       TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
	break;
      case TPM_CAP_PROP_MAX_DAASESS:	/* The maximum number of loaded DAA sessions (join or sign)
					   that the TPM supports */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_MAX\n");
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_DAA_SESSIONS);
	break;
      case TPM_CAP_PROP_DAASESS:	/* The number of available DAA sessions. This may vary with
					   time and circumstances */
	TPM_DaaSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.daaSessions);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSION_DAA space %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_CONTEXT_DIST:	/* The maximum distance between context count values. This
					   MUST be at least 2^16-1. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT_DIST\n");
	rc = TPM_Sbuffer_Append32(capabilityResponse, 0xffffffff);
	break;
      case TPM_CAP_PROP_DAA_INTERRUPT:	/* BOOL. A value of TRUE indicates that the TPM will accept
					   ANY command while executing a DAA Join or Sign.

					   A value of FALSE indicates that the TPM will invalidate
					   the DAA Join or Sign upon the receipt of any command
					   other than the next join/sign in the session or a
					   TPM_SaveContext */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_INTERRUPT\n");
	rc = TPM_Sbuffer_Append8(capabilityResponse, TRUE);   
	break;
      case TPM_CAP_PROP_SESSIONS: /* UNIT32. The number of available authorization and transport
				     sessions from the pool. This may vary with time and
				     circumstances. */
	TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions);
	TPM_TransportSessions_GetSpace(&uint32a, tpm_state->tpm_stclear_data.transSessions);
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSIONS %u + %u\n", uint32, uint32a);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32 + uint32a);
	break;
      case TPM_CAP_PROP_MAX_SESSIONS: /* uint32_t. The maximum number of sessions the
					 TPM supports. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_SESSIONS\n");
	rc = TPM_Sbuffer_Append32(capabilityResponse,
				  TPM_MIN_AUTH_SESSIONS + TPM_MIN_TRANS_SESSIONS);
	break;
      case TPM_CAP_PROP_CMK_RESTRICTION: /* uint32_t TPM_Permanent_Data -> restrictDelegate */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CMK_RESTRICTION %08x\n",
	       tpm_state->tpm_permanent_data.restrictDelegate);
	rc = TPM_Sbuffer_Append32(capabilityResponse,
				  tpm_state->tpm_permanent_data.restrictDelegate);
	break;
      case TPM_CAP_PROP_DURATION: 
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DURATION\n");
	rc = TPM_GetCapability_CapPropDuration(capabilityResponse);
	break;
      case TPM_CAP_PROP_ACTIVE_COUNTER: /* TPM_COUNT_ID. The id of the current counter. 0xff..ff if
					   no counter is active */
	TPM_Counters_GetActiveCounter(&uint32, tpm_state->tpm_stclear_data.countID);
	/* The illegal value after releasing an active counter must be mapped back to the null
	   value */
	if (uint32 == TPM_COUNT_ID_ILLEGAL) {
	    uint32 = TPM_COUNT_ID_NULL;
	}
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_ACTIVE_COUNTER %u\n", uint32);
	rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	break;
      case TPM_CAP_PROP_MAX_NV_AVAILABLE: /* uint32_t. Deprecated.  The maximum number of NV space
					     that can be allocated, MAY vary with time and
					     circumstances.  This capability was not implemented
					     consistently, and is replaced by
					     TPM_NV_INDEX_TRIAL.  */
	rc = TPM_NVIndexEntries_GetFreeSpace(&uint32, &(tpm_state->tpm_nv_index_entries));
	if (rc == 0) {
	    printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_NV_AVAILABLE %u\n", uint32);
	    rc = TPM_Sbuffer_Append32(capabilityResponse, uint32);
	}
	/* There should always be free space >= 0.  If the call fails here, there is an internal
	   error. */
	else {
	    printf(" TPM_GetCapability_CapProperty: Error (fatal) "
		   "in TPM_CAP_PROP_MAX_NV_AVAILABLE\n");
	    rc = TPM_FAIL;
	}
	break;
      case TPM_CAP_PROP_INPUT_BUFFER: /* uint32_t. The size of the TPM input and output buffers in
					 bytes. */
	printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_INPUT_BUFFER %u\n",
	       TPM_BUFFER_MAX);
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_BUFFER_MAX);
	break;
     default:
	printf("TPM_GetCapability_CapProperty: Error, illegal capProperty %08x\n", capProperty);
	rc = TPM_BAD_MODE;
	break;
    }
    return rc;
}    

/* TPM_VERSION structure. The Major and Minor must indicate 1.1.

   The manufacturer information MUST indicate the firmware version of the TPM.

   Any software using this structure MUST be aware that when included in a structure the value MUST
   be 1.1.0.0, when reported by this command the manufacturer information MAY include firmware
   versions.  The use of this value is deprecated, new software SHOULD use TPM_CAP_VERSION_VAL to
   obtain version information regarding the TPM.
   
   Return 0.0 for revision for 1.1 backward compatibility, since TPM_PERMANENT_DATA now holds the
   new type TPM_VERSION_BYTE.
*/

static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse)
{
    TPM_RESULT	rc = 0;
    TPM_STRUCT_VER	tpm_struct_ver;

    TPM_StructVer_Init(&tpm_struct_ver);
    printf(" TPM_GetCapability_CapVersion: %u.%u.%u.%u\n",
	   tpm_struct_ver.major, tpm_struct_ver.minor,
	   tpm_struct_ver.revMajor, tpm_struct_ver.revMinor);
    rc = TPM_StructVer_Store(capabilityResponse, &tpm_struct_ver);
    return rc;
}

/* A Boolean value.

   TRUE indicates that the TPM has enough memory available to load a key of the type specified by
   ALGORITHM.

   FALSE indicates that the TPM does not have enough memory.
*/

static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse,
						   const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry,
						   TPM_SIZED_BUFFER *subCap)
{
    TPM_RESULT		rc = 0;
    uint32_t		stream_size;
    unsigned char	*stream;
    TPM_KEY_PARMS	keyParms;
    TPM_BOOL		isSpace;
    uint32_t		index;

    TPM_KeyParms_Init(&keyParms);		/* freed @1 */
    if (rc == 0) {
	/* make temporary copies so the subCap is not touched */
	stream = subCap->buffer;
	stream_size = subCap->size;
	rc = TPM_KeyParms_Load(&keyParms, &stream, &stream_size);
    }
    if (rc == 0) {
	if (keyParms.algorithmID == TPM_ALG_RSA) {
	    TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entry);
	}
	else {
	    printf(" TPM_GetCapability_CapCheckLoaded: algorithmID %08x is not TPM_ALG_RSA %08x\n",
		   keyParms.algorithmID, TPM_ALG_RSA);
	    isSpace = FALSE;
	}
    }
    if (rc == 0) {
	printf(" TPM_GetCapability_CapCheckLoaded: Return %02x\n", isSpace);
	rc = TPM_Sbuffer_Append(capabilityResponse, &isSpace, sizeof(TPM_BOOL));
    }
    TPM_KeyParms_Delete(&keyParms);		/* @1 */
    return rc;
}

/* (Deprecated) This indicates the mode of a symmetric encryption. Mode is Electronic CookBook (ECB)
   or some other such mechanism.
*/

static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_SYM_MODE symMode)
{
    TPM_RESULT	rc = 0;
    
    symMode = symMode;	/* not currently used */
    printf(" TPM_GetCapability_CapSymMode: Return %02x\n", FALSE);
    rc = TPM_Sbuffer_Append8(capabilityResponse, FALSE);
    return rc;
}

/* Boolean value of ownerEvict. The handle MUST point to a valid key handle.
 */

static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse,
						 TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries,
						 uint32_t tpm_key_handle)
{
    TPM_RESULT			rc = 0;
    TPM_KEY_HANDLE_ENTRY	*tpm_key_handle_entry;	/* corresponding to handle */
    TPM_BOOL			ownerEvict;
    
    printf(" TPM_GetCapability_CapKeyStatus: key handle %08x\n", tpm_key_handle);
    /* map from the handle to the TPM_KEY structure */
    if (rc == 0) {
	rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry,
					   tpm_key_handle_entries,
					   tpm_key_handle);
	if (rc != 0) {
	    printf("TPM_GetCapability_CapKeyStatus: Error, key handle %08x not found\n",
		   tpm_key_handle);
	}
    }
    /* test the ownerEvict bit */
    if (rc == 0) {
	ownerEvict = (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) ?
		     TRUE : FALSE;;
	printf(" TPM_GetCapability_CapKeyStatus: return %02x\n", ownerEvict);
	rc = TPM_Sbuffer_Append(capabilityResponse, &ownerEvict, sizeof(TPM_BOOL));
    }
    return rc;
}

/* Manufacturer specific. The manufacturer may provide any additional information regarding the TPM
   and the TPM state but MUST not expose any sensitive information.
*/

static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse,
					   tpm_state_t *tpm_state,
					   TPM_SIZED_BUFFER *subCap)
{
    TPM_RESULT	rc = 0;
    uint32_t	subCap32;
    
    /* all of the subCaps are at least a uint32_t.  Some have more data */
    if (rc == 0) {
	if (subCap->size >= sizeof(uint32_t)) {
	    subCap32 = htonl(*(uint32_t *)subCap->buffer);
	    printf(" TPM_GetCapability_CapMfr: subCap %08x\n", subCap32);
	}
	else {
	    printf("TPM_GetCapability_CapMfr: Error, subCap size %u < %lu\n",
		   subCap->size, (unsigned long)sizeof(uint32_t));
	    rc = TPM_BAD_MODE;
	}
    }
    /* switch on the subCap and append the get capability response to the capabilityResponse
       buffer */
    if (rc == 0) {
	switch(subCap32) {
#ifdef TPM_POSIX
	  case TPM_CAP_PROCESS_ID:
	    if (subCap->size == sizeof(uint32_t)) {
		pid_t pid = getpid();
		printf(" TPM_GetCapability_CapMfr: TPM_CAP_PROCESS_ID %u\n", (uint32_t)pid);
		rc = TPM_Sbuffer_Append32(capabilityResponse, (uint32_t)pid);
	    }
	    else {
		printf("TPM_GetCapability_CapMfr: Error, Bad subCap size %u\n", subCap->size);
		rc = TPM_BAD_MODE;
	    }
	    break;
#endif
	  default:
	    capabilityResponse = capabilityResponse;	/* not used */
	    tpm_state = tpm_state;			/* not used */
	    printf("TPM_GetCapability_CapMfr: Error, unsupported subCap %08x\n", subCap32);
	    rc = TPM_BAD_MODE;
	    break;
	}
    }
    return rc;
}

/* Returns a TPM_NV_DATA_PUBLIC structure that indicates the values for the TPM_NV_INDEX
*/

static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse,
					       tpm_state_t *tpm_state,
					       uint32_t nvIndex)
{
    TPM_RESULT		rc = 0;
    TPM_NV_DATA_PUBLIC 	*tpm_nv_data_public;
    
    printf(" TPM_GetCapability_CapNVIndex: nvIndex %08x\n", nvIndex);
    /* map from the nvIndex to the TPM_NV_DATA_PUBLIC structure */
    if (rc == 0) {
	rc = TPM_NVIndexEntries_GetDataPublic(&tpm_nv_data_public,
					      &(tpm_state->tpm_nv_index_entries),
					      nvIndex);
    }
    /* serialize the structure */
    if (rc == 0) {
	rc = TPM_NVDataPublic_Store(capabilityResponse, tpm_nv_data_public,
				    FALSE);	/* do not optimize digestAtRelease */
    }
    return rc;
}

/* Returns a Boolean value.

   TRUE means that the TPM supports the algorithm for TPM_EstablishTransport, TPM_ExecuteTransport
   and TPM_ReleaseTransportSigned.

   FALSE indicates that for these three commands the algorithm is not supported."
*/

static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse,
						TPM_ALGORITHM_ID algorithmID)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	supported;

    printf(" TPM_GetCapability_CapTransAlg: algorithmID %08x\n", algorithmID);
    TPM_TransportPublic_CheckAlgId(&supported, algorithmID);
    printf("  TPM_GetCapability_CapTransAlg: Result %08x\n", supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}

/* Returns a TPM_KEY_HANDLE_LIST structure that enumerates all handles currently loaded in the TPM
   for the given resource type.

   TPM_KEY_HANDLE_LIST is the number of handles followed by a list of the handles.

   When describing keys the handle list only contains the number of handles that an external manager
   can operate with and does not include the EK or SRK.

   Legal resources are TPM_RT_KEY, TPM_RT_AUTH, TPM_RT_TRANS, TPM_RT_COUNTER

   TPM_RT_CONTEXT is valid and returns not a list of handles but a list of the context count values.
*/

static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse,
					      tpm_state_t *tpm_state,
					      TPM_RESOURCE_TYPE resourceType)
{
    TPM_RESULT	rc = 0;

    printf(" TPM_GetCapability_CapHandle: resourceType %08x\n", resourceType);
    switch (resourceType) {
      case TPM_RT_KEY:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_KEY\n");
	rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse,
					       tpm_state->tpm_key_handle_entries);
	break;
      case TPM_RT_AUTH:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_AUTH\n");
	rc = TPM_AuthSessions_StoreHandles(capabilityResponse,
					   tpm_state->tpm_stclear_data.authSessions);
	break;
      case TPM_RT_TRANS:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_TRANS\n");
	rc = TPM_TransportSessions_StoreHandles(capabilityResponse,
						tpm_state->tpm_stclear_data.transSessions);
	break;
      case TPM_RT_CONTEXT:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_CONTEXT\n");
	rc = TPM_ContextList_StoreHandles(capabilityResponse,
					  tpm_state->tpm_stclear_data.contextList);
	break;
      case TPM_RT_COUNTER:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_COUNTER\n");
	rc = TPM_Counters_StoreHandles(capabilityResponse,
				       tpm_state->tpm_permanent_data.monotonicCounter);
	break;
      case TPM_RT_DAA_TPM:
	printf("  TPM_GetCapability_CapHandle: TPM_RT_DAA_TPM\n");
	rc = TPM_DaaSessions_StoreHandles(capabilityResponse,
					  tpm_state->tpm_stclear_data.daaSessions);
	break;
      default:
	printf("TPM_GetCapability_CapHandle: Error, illegal resource type %08x\n",
	       resourceType);
	rc = TPM_BAD_PARAMETER;
    }
    return rc;
}

/* Returns Boolean value.

   TRUE means the TPM supports the encryption scheme in a transport session.
*/

static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_ENC_SCHEME encScheme)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	supported;

    printf(" TPM_GetCapability_CapTransEs: encScheme %04hx\n", encScheme);
    switch (encScheme) {
	/* supported protocols */
      case TPM_ES_SYM_CTR:
      case TPM_ES_SYM_OFB:
	supported = TRUE;
	break;
	/* unsupported protocols */
      case TPM_ES_RSAESPKCSv15:
      case TPM_ES_RSAESOAEP_SHA1_MGF1:
      default:
	supported = FALSE;
	break;
    }	
    printf("  TPM_GetCapability_CapTransEs: Result %08x\n", supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}

/* Boolean value.

   TRUE indicates that the TPM supports the encryption algorithm in OSAP encryption of AuthData
   values
*/

static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse,
						   TPM_ALGORITHM_ID algorithmID)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	supported;

    printf(" TPM_GetCapability_CapAuthEncrypt: algorithmID %08x\n", algorithmID);
    switch (algorithmID) {
      case TPM_ALG_XOR:
      case TPM_ALG_AES128:
	/* supported protocols */
	supported = TRUE;
	break;
      case TPM_ALG_RSA:
      case TPM_ALG_SHA:
      case TPM_ALG_HMAC:
      case TPM_ALG_MGF1:
      case TPM_ALG_AES192:
      case TPM_ALG_AES256:
      default:
	/* unsupported protocols */
	supported = FALSE;
	break;
    }	
    printf("  TPM_GetCapability_CapAuthEncrypt: Result %08x\n", supported);
    rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    return rc;
}

/* Boolean value.

   TRUE indicates that the TPM supports the size for the given version.

   For instance a request could ask for version 1.1 size 2 and the TPM would indicate TRUE. For 1.1
   size 3 the TPM would indicate FALSE. For 1.2 size 3 the TPM would indicate TRUE.
*/

static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse,
						  TPM_SIZED_BUFFER *subCap)
{
    TPM_RESULT		rc = 0;
    TPM_SELECT_SIZE	tpm_select_size;
    unsigned char	*stream;
    uint32_t		stream_size;
    TPM_BOOL		supported;

    printf(" TPM_GetCapability_CapSelectSize:\n");
    TPM_SelectSize_Init(&tpm_select_size);		/* no free required */
    /* deserialize the subCap to the structure */
    if (rc == 0) {
	stream = subCap->buffer;
	stream_size = subCap->size;
	rc = TPM_SelectSize_Load(&tpm_select_size, &stream , &stream_size);
    }
    if (rc == 0) {
	/* The TPM MUST return an error if sizeOfSelect is 0 */
	printf("  TPM_GetCapability_CapSelectSize: subCap reqSize %u\n",
	       tpm_select_size.reqSize);
	if ((tpm_select_size.reqSize > (TPM_NUM_PCR/CHAR_BIT)) ||
	    (tpm_select_size.reqSize == 0)) {
	    supported = FALSE;
	}
	else {
	    supported = TRUE;
	}
    }
    if (rc == 0) {
	printf("  TPM_GetCapability_CapSelectSize: Result %08x\n", supported);
	rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL));
    }
    return rc;
}

#if  (TPM_REVISION >= 103)	/* added for rev 103 */
/* TPM_GetCapability_CapDaLogic() rev 100

   A TPM_DA_INFO or TPM_DA_INFO_LIMITED structure that returns data according to the selected entity
   type (e.g., TPM_ET_KEYHANDLE, TPM_ET_OWNER, TPM_ET_SRK, TPM_ET_COUNTER, TPM_ET_OPERATOR,
   etc.). If the implemented dictionary attack logic does not support different secret types, the
   entity type can be ignored.
*/

static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse,
					       TPM_SIZED_BUFFER *subCap,
					       tpm_state_t *tpm_state)
{
    TPM_RESULT		rc = 0;
    TPM_DA_INFO_LIMITED tpm_da_info_limited;
    TPM_DA_INFO		tpm_da_info;

    printf(" TPM_GetCapability_CapDaLogic:\n");
    TPM_DaInfoLimited_Init(&tpm_da_info_limited);	/* freed @1 */
    TPM_DaInfo_Init(&tpm_da_info);			/* freed @2 */
    subCap = subCap;			/* dictionary attack mitigation not per entity type in this
					   implementation. */
    /* if disableFullDALogicInfo is TRUE, the full dictionary attack TPM_GetCapability info is
       deactivated.  The returned structure is TPM_DA_INFO_LIMITED. */
    if (tpm_state->tpm_permanent_flags.disableFullDALogicInfo) {
	TPM_DaInfoLimited_Set(&tpm_da_info_limited, tpm_state);
	rc = TPM_DaInfoLimited_Store(capabilityResponse, &tpm_da_info_limited);
	
    }
    /* if disableFullDALogicInfo is FALSE, the full dictionary attack TPM_GetCapability 
       info is activated.  The returned structure is 
       TPM_DA_INFO. */
    else {
	TPM_DaInfo_Set(&tpm_da_info, tpm_state);
	rc = TPM_DaInfo_Store(capabilityResponse, &tpm_da_info);
    }
    TPM_DaInfoLimited_Delete(&tpm_da_info_limited);	/* @1 */
    TPM_DaInfo_Delete(&tpm_da_info);			/* @2 */
    return rc;
}
#endif

/* Returns TPM_CAP_VERSION_INFO structure.

   The TPM fills in the structure and returns the information indicating what the TPM currently
   supports.
*/

static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse,
						  TPM_PERMANENT_DATA *tpm_permanent_data)
{
    TPM_RESULT			rc = 0;
    TPM_CAP_VERSION_INFO	tpm_cap_version_info;

    printf(" TPM_GetCapability_CapVersionVal:\n");
    TPM_CapVersionInfo_Set(&tpm_cap_version_info, tpm_permanent_data);	/* freed @1 */
    printf("  TPM_GetCapability_CapVersionVal: specLevel %04hx\n", tpm_cap_version_info.specLevel);
    printf("  TPM_GetCapability_CapVersionVal: errataRev %02x\n", tpm_cap_version_info.errataRev);
    printf("  TPM_GetCapability_CapVersionVal: revMajor %02x revMinor %02x\n",
	   tpm_cap_version_info.version.revMajor, tpm_cap_version_info.version.revMinor);
    printf("  TPM_GetCapability_CapVersionVal: tpmVendorID %02x %02x %02x %02x\n",
	   tpm_cap_version_info.tpmVendorID[0],
	   tpm_cap_version_info.tpmVendorID[1],
	   tpm_cap_version_info.tpmVendorID[2],
	   tpm_cap_version_info.tpmVendorID[3]);
    rc = TPM_CapVersionInfo_Store(capabilityResponse, &tpm_cap_version_info);
    TPM_CapVersionInfo_Delete(&tpm_cap_version_info);			/* @1 */
    return rc;
}

/* Returns a 4 element array of uint32_t values each denoting the timeout value in microseconds for
   the following in this order:
							 
   TIMEOUT_A, TIMEOUT_B, TIMEOUT_C, TIMEOUT_D

   Where these timeouts are to be used is determined by the platform specific TPM Interface
   Specification.
*/

static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse)
{
    TPM_RESULT			rc = 0;

    printf(" TPM_GetCapability_CapPropTisTimeout:\n");
    if (rc == 0) { 
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_A);
    }								   
    if (rc == 0) {						   
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_B);
    }								   
    if (rc == 0) {						   
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_C);
    }								   
    if (rc == 0) {						   
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_D);
    }
    return rc;
}

/* Returns a 3 element array of uint32_t values each denoting the duration value in microseconds of
   the duration of the three classes of commands: Small, Medium and Long in the following in this
   order:

   SMALL_DURATION, MEDIUM_DURATION, LONG_DURATION
*/

static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse)
{
    TPM_RESULT			rc = 0;

    printf(" TPM_GetCapability_CapPropDuration:\n");
    if (rc == 0) { 
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_SMALL_DURATION);
    }								   
    if (rc == 0) {						   
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MEDIUM_DURATION);
    }								   
    if (rc == 0) {						   
	rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_LONG_DURATION);
    }								   
    return rc;
}

/* 7.3 TPM_GetCapabilityOwner rev 98

   TPM_GetCapabilityOwner enables the TPM Owner to retrieve all the non-volatile flags and the
   volatile flags in a single operation.  This command is deprecated, mandatory.

   The flags summarize many operational aspects of the TPM. The information represented by some
   flags is private to the TPM Owner. So, for simplicity, proof of ownership of the TPM must be
   presented to retrieve the set of flags. When necessary, the flags that are not private to the
   Owner can be deduced by Users via other (more specific) means.
   
   The normal TPM authentication mechanisms are sufficient to prove the integrity of the
   response. No additional integrity check is required.

   For 31>=N>=0

   1. Bit-N of the TPM_PERMANENT_FLAGS structure is the Nth bit after the opening bracket in the
   definition of TPM_PERMANENT_FLAGS in the version of the specification indicated by the parameter
   "version". The bit immediately after the opening bracket is the 0th bit.

   2. Bit-N of the TPM_STCLEAR_FLAGS structure is the Nth bit after the opening bracket in the
   definition of TPM_STCLEAR_FLAGS in the version of the specification indicated by the parameter
   "version". The bit immediately after the opening bracket is the 0th bit.

   3. Bit-N of non_volatile_flags corresponds to the Nth bit in TPM_PERMANENT_FLAGS, and the lsb of
   non_volatile_flags corresponds to bit0 of TPM_PERMANENT_FLAGS

   4. Bit-N of volatile_flags corresponds to the Nth bit in TPM_STCLEAR_FLAGS, and the lsb of
   volatile_flags corresponds to bit0 of TPM_STCLEAR_FLAGS
*/

TPM_RESULT TPM_Process_GetCapabilityOwner(tpm_state_t *tpm_state,
					  TPM_STORE_BUFFER *response,
					  TPM_TAG tag,
					  uint32_t paramSize,
					  TPM_COMMAND_CODE ordinal,
					  unsigned char *command,
					  TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT	rcf = 0;			/* fatal error precluding response */
    TPM_RESULT	returnCode = TPM_SUCCESS;	/* command return code */

    /* input parameters */
    TPM_AUTHHANDLE	authHandle;	/* The authorization session handle used for Owner
					   authentication. */
    TPM_NONCE		nonceOdd;	/* Nonce generated by system associated with authHandle */
    TPM_BOOL	continueAuthSession = TRUE;	/* The continue use flag for the authorization
						   session */
    TPM_AUTHDATA	ownerAuth;	/* The authorization session digest for inputs and owner
					   authentication. HMAC key: ownerAuth. */

    /* processing parameters */
    unsigned char *	inParamStart;	/* starting point of inParam's */
    unsigned char *	inParamEnd;	/* ending point of inParam's */
    TPM_DIGEST		inParamDigest;
    TPM_BOOL		auditStatus;		/* audit the ordinal */
    TPM_BOOL		transportEncrypt;	/* wrapped in encrypted transport session */
    TPM_BOOL		authHandleValid = FALSE;
    TPM_AUTH_SESSION_DATA *auth_session_data;	/* session data for authHandle */
    TPM_SECRET		*hmacKey;

    /* output parameters */
    uint32_t		outParamStart;		/* starting point of outParam's */
    uint32_t		outParamEnd;		/* ending point of outParam's */
    TPM_DIGEST		outParamDigest;
    TPM_VERSION		version;		/* A properly filled out version structure. */
    uint32_t		non_volatile_flags;	/* The current state of the non-volatile flags. */
    uint32_t		volatile_flags;		/* The current state of the volatile flags. */

    printf("TPM_Process_GetCapabilityOwner: Ordinal Entry\n");
    /*
      get inputs
    */
    /* save the starting point of inParam's for authorization and auditing */
    inParamStart = command;
    /* save the ending point of inParam's for authorization and auditing */
    inParamEnd = command;
    /* digest the input parameters */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_GetInParamDigest(inParamDigest,	/* output */
					  &auditStatus,		/* output */
					  &transportEncrypt,	/* output */
					  tpm_state,
					  tag,
					  ordinal,
					  inParamStart,
					  inParamEnd,
					  transportInternal);
    }
    /* check state */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
    }
    /* check tag */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckRequestTag1(tag);
    }
    /* get the 'below the line' authorization parameters */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_AuthParams_Get(&authHandle,
					&authHandleValid,
					nonceOdd,
					&continueAuthSession,
					ownerAuth,
					&command, &paramSize);
    }
    if (returnCode == TPM_SUCCESS) {
	if (paramSize != 0) {
	    printf("TPM_Process_GetCapabilityOwner: Error, command has %u extra bytes\n",
		   paramSize);
	    returnCode = TPM_BAD_PARAM_SIZE;
	}
    }
    /* do not terminate sessions if the command did not parse correctly */
    if (returnCode != TPM_SUCCESS) {
	authHandleValid = FALSE;
    }
    /*
      Processing
    */
    /* 1. The TPM validates that the TPM Owner authorizes the command. */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_AuthSessions_GetData(&auth_session_data,
					      &hmacKey,
					      tpm_state,
					      authHandle,
					      TPM_PID_NONE,
					      TPM_ET_OWNER,
					      ordinal,
					      NULL,
					      &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */
					      tpm_state->tpm_permanent_data.ownerAuth);	  /* OSAP */
    }
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Authdata_Check(tpm_state,
					*hmacKey,		/* owner HMAC key */
					inParamDigest,
					auth_session_data,	/* authorization session */
					nonceOdd,		/* Nonce generated by system
								   associated with authHandle */
					continueAuthSession,
					ownerAuth);		/* Authorization digest for input */
    }
    /* 2. The TPM creates the parameter non_volatile_flags by setting each bit to the same state as
       the corresponding bit in TPM_PERMANENT_FLAGS. Bits in non_volatile_flags for which there is
       no corresponding bit in TPM_PERMANENT_FLAGS are set to zero. */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_PermanentFlags_StoreBitmap(&non_volatile_flags,
						    &(tpm_state->tpm_permanent_flags));
    }	 
    /* 3. The TPM creates the parameter volatile_flags by setting each bit to the same state as the
       corresponding bit in TPM_STCLEAR_FLAGS. Bits in volatile_flags for which there is no
       corresponding bit in TPM_STCLEAR_FLAGS are set to zero. */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_StclearFlags_StoreBitmap(&volatile_flags,
						  &(tpm_state->tpm_stclear_flags));
    }	 
    /* 4. The TPM generates the parameter "version". */
    if (returnCode == TPM_SUCCESS) {
	TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data));
    }	 
    /* 5. The TPM returns non_volatile_flags, volatile_flags and version to the caller. */
    /*
      response
    */
    /* standard response: tag, (dummy) paramSize, returnCode.  Failure is fatal. */
    if (rcf == 0) {
	printf("TPM_Process_GetCapabilityOwner: Ordinal returnCode %08x %u\n",
	       returnCode, returnCode);
	rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
    }
    /* success response, append the rest of the parameters.  */
    if (rcf == 0) {
	if (returnCode == TPM_SUCCESS) {
	    /* checkpoint the beginning of the outParam's */
	    outParamStart = response->buffer_current - response->buffer;
	    /* return the version */
	    returnCode = TPM_Version_Store(response, &version);
	}
	/* return the non_volatile_flags */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_Sbuffer_Append32(response, non_volatile_flags);
	}
	/* return the volatile_flags */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_Sbuffer_Append32(response, volatile_flags);
	    /* checkpoint the end of the outParam's */
	    outParamEnd = response->buffer_current - response->buffer;
	}
	/* digest the above the line output parameters */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_GetOutParamDigest(outParamDigest,	/* output */
					       auditStatus,	/* input audit status */
					       transportEncrypt,
					       tag,			
					       returnCode,
					       ordinal,		/* command ordinal */
					       response->buffer + outParamStart,	/* start */
					       outParamEnd - outParamStart);	/* length */
	}
	/* calculate and set the below the line parameters */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_AuthParams_Set(response,
					    *hmacKey,	/* owner HMAC key */
					    auth_session_data,
					    outParamDigest,
					    nonceOdd,
					    continueAuthSession);
	}
	/* audit if required */
	if ((returnCode == TPM_SUCCESS) && auditStatus) {
	    returnCode = TPM_ProcessAudit(tpm_state,
					  transportEncrypt,
					  inParamDigest,
					  outParamDigest,
					  ordinal);
	}
	/* adjust the initial response */
	rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
    }
    /* if there was an error, or continueAuthSession is FALSE, terminate the session */
    if (((rcf != 0) ||
	 ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
	 !continueAuthSession) &&
	authHandleValid) {
	TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
    }
    /*
      cleanup
    */
    return rcf;
}

/* 29.1 TPM_GetCapabilitySigned rev 94

   TPM_GetCapabilitySigned is almost the same as TPM_GetCapability. The differences are that the
   input includes a challenge (a nonce) and the response includes a digital signature to vouch for
   the source of the answer.

   If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM
   and the caller have AuthData.

   If a caller requires proof for a third party, the signing key must be one whose signature is
   trusted by the third party. A TPM-identity key may be suitable.
*/

TPM_RESULT TPM_Process_GetCapabilitySigned(tpm_state_t *tpm_state,
					   TPM_STORE_BUFFER *response,
					   TPM_TAG tag,
					   uint32_t paramSize,
					   TPM_COMMAND_CODE ordinal,
					   unsigned char *command,
					   TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT	rcf = 0;			/* fatal error precluding response */
    TPM_RESULT	returnCode = TPM_SUCCESS;	/* command return code */

    /* input parameters */
    TPM_KEY_HANDLE	keyHandle;	/* The handle of a loaded key that can perform digital
					   signatures. */
    TPM_NONCE		antiReplay;	/* Nonce provided to allow caller to defend against replay
					   of messages */
    TPM_CAPABILITY_AREA capArea = 0;	/* Partition of capabilities to be interrogated */
    TPM_SIZED_BUFFER	subCap;		/* Further definition of information */
    TPM_AUTHHANDLE	authHandle;	/* The authorization session handle used for keyHandle
					   authorization */
    TPM_NONCE		nonceOdd;	/* Nonce generated by system associated with authHandle */
    TPM_BOOL	continueAuthSession = TRUE;	/* The continue use flag for the authorization
						   session handle */
    TPM_AUTHDATA	privAuth;	/* The authorization session digest that authorizes the use
					   of keyHandle. HMAC key: key.usageAuth */
   
    /* processing parameters */
    unsigned char *	inParamStart;		/* starting point of inParam's */
    unsigned char *	inParamEnd;		/* ending point of inParam's */
    TPM_DIGEST		inParamDigest;
    TPM_BOOL		auditStatus;		/* audit the ordinal */
    TPM_BOOL		transportEncrypt;	/* wrapped in encrypted transport session */
    TPM_BOOL		authHandleValid = FALSE;
    TPM_AUTH_SESSION_DATA *auth_session_data;	/* session data for authHandle */
    TPM_SECRET		*hmacKey;
    TPM_KEY		*sigKey = NULL;		/* the key specified by keyHandle */
    TPM_SECRET		*keyUsageAuth;
    TPM_BOOL		parentPCRStatus;
    uint16_t		subCap16;		/* the subCap as a uint16_t */
    uint32_t		subCap32;		/* the subCap as a uint32_t */
    TPM_STORE_BUFFER	r1Response;		/* capability response */
    const unsigned char *r1_buffer;		/* r1 serialization */
    uint32_t		r1_length;
    TPM_DIGEST		s1;

    /* output parameters */
    uint32_t		outParamStart;	/* starting point of outParam's */
    uint32_t		outParamEnd;	/* ending point of outParam's */
    TPM_DIGEST		outParamDigest;
    TPM_VERSION		version;	/* A properly filled out version structure. */
    TPM_SIZED_BUFFER	resp;		/* The capability response */
    TPM_SIZED_BUFFER	sig;		/* The resulting digital signature. */

    printf("TPM_Process_GetCapabilitySigned: Ordinal Entry\n");
    TPM_SizedBuffer_Init(&subCap);	/* freed @1 */
    TPM_SizedBuffer_Init(&resp);	/* freed @2 */
    TPM_SizedBuffer_Init(&sig);		/* freed @3 */
    TPM_Sbuffer_Init(&r1Response);	/* freed @4 */
    /*
      get inputs
    */
    /* get keyHandle parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
    }
    /* save the starting point of inParam's for authorization and auditing */
    inParamStart = command;
    /* get antiReplay parameter */
    if (returnCode == TPM_SUCCESS) {
	printf("TPM_Process_GetCapabilitySigned: keyHandle %08x\n", keyHandle);
	returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
    }
    /* get capArea parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Load32(&capArea, &command, &paramSize);
    }
    /* get get subCap parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
    }
    /* save the ending point of inParam's for authorization and auditing */
    inParamEnd = command;
    /* digest the input parameters */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_GetInParamDigest(inParamDigest,	/* output */
					  &auditStatus,		/* output */
					  &transportEncrypt,	/* output */
					  tpm_state,
					  tag,
					  ordinal,
					  inParamStart,
					  inParamEnd,
					  transportInternal);
    }
    /* check state */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
    }
    /* check tag */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckRequestTag10(tag);
    }
    /* get the optional 'below the line' authorization parameters */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_AuthParams_Get(&authHandle,
					&authHandleValid,
					nonceOdd,
					&continueAuthSession,
					privAuth,
					&command, &paramSize);
    }
    if (returnCode == TPM_SUCCESS) {
	if (paramSize != 0) {
	    printf("TPM_Process_GetCapabilitySigned: Error, command has %u extra bytes\n",
		   paramSize);
	    returnCode = TPM_BAD_PARAM_SIZE;
	}
    }
    /* do not terminate sessions if the command did not parse correctly */
    if (returnCode != TPM_SUCCESS) {
	authHandleValid = FALSE;
    }
    /*
      Processing
    */
    /* get the key corresponding to the keyHandle parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle,
						 FALSE,		/* not r/o, used to sign */
						 FALSE,		/* do not ignore PCRs */
						 FALSE);	/* cannot use EK */
    }
    /* 1. The TPM validates the authority to use keyHandle */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) {
	if (sigKey->authDataUsage != TPM_AUTH_NEVER) {
	    printf("TPM_Process_GetCapabilitySigned: Error, authorization required\n");
	    returnCode = TPM_AUTHFAIL;
	}
    }
    /* get keyHandle -> usageAuth */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey);
    }	 
    /* get the session data */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_AuthSessions_GetData(&auth_session_data,
					      &hmacKey,
					      tpm_state,
					      authHandle,
					      TPM_PID_NONE,
					      TPM_ET_KEYHANDLE,
					      ordinal,
					      sigKey,
					      keyUsageAuth,		/* OIAP */
					      sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */
    }
    /* 1. The TPM MUST validate the authorization to use the key pointed to by keyHandle. */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_Authdata_Check(tpm_state,
					*hmacKey,		/* HMAC key */
					inParamDigest,
					auth_session_data,	/* authorization session */
					nonceOdd,		/* Nonce generated by system
								   associated with authHandle */
					continueAuthSession,
					privAuth);		/* Authorization digest for input */
    }
    

    /* subCap is often a uint16_t or uint32_t, create them now */
    if (returnCode == TPM_SUCCESS) {
	TPM_GetSubCapInt(&subCap16, &subCap32, &subCap);
    }
    /* 2. The TPM calls TPM_GetCapability passing the capArea and subCap fields and saving the resp
       field as R1 */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_GetCapabilityCommon(&r1Response, tpm_state,
					     capArea, subCap16, subCap32, &subCap);
    }	 
    if (returnCode == TPM_SUCCESS) {
	/* get the capability r1 serialization */
	TPM_Sbuffer_Get(&r1Response, &r1_buffer, &r1_length);
	printf("TPM_Process_GetCapabilitySigned: resp length %08x\n", r1_length);
	TPM_PrintFour("TPM_Process_GetCapabilitySigned: Hashing resp", r1_buffer);
	TPM_PrintFour("TPM_Process_GetCapabilitySigned: antiReplay", antiReplay);
	/* 3. The TPM creates S1 by taking a SHA1 hash of the concatenation (r1 || antiReplay).	 */
	returnCode = TPM_SHA1(s1,
			      r1_length, r1_buffer,
			      TPM_NONCE_SIZE, antiReplay,
			      0, NULL);
    }	 
    /* 4. The TPM validates the authority to use keyHandle */
    /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or
       TPM_KEY_IDENTITY. */
    if (returnCode == TPM_SUCCESS) {
	if ((sigKey->keyUsage != TPM_KEY_SIGNING) &&
	    ((sigKey->keyUsage) != TPM_KEY_IDENTITY) &&
	    ((sigKey->keyUsage) != TPM_KEY_LEGACY)) {
	    printf("TPM_Process_GetCapabilitySigned: Error, keyUsage %04hx is invalid\n",
		   sigKey->keyUsage);
	    returnCode = TPM_INVALID_KEYUSAGE;
	}
    }
    /* 5. The TPM creates a digital signature of S1 using the key in keyHandle and returns the
       result in sig. */
    if (returnCode == TPM_SUCCESS) {
	if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) {
	    printf("TPM_Process_GetCapabilitySigned: Error, inappropriate signature scheme %04x\n",
		   sigKey->algorithmParms.sigScheme);
	    returnCode = TPM_INAPPROPRIATE_SIG;
	}
    }
    if (returnCode == TPM_SUCCESS) {
	TPM_PrintFour("TPM_Process_GetCapabilitySigned: Signing s1", s1);
	returnCode = TPM_RSASignToSizedBuffer(&sig,		/* signature */
					      s1,		/* message */
					      TPM_DIGEST_SIZE,	/* message size */
					      sigKey);		/* signing key and parameters */
    }
    /*
      response
    */
    /* standard response: tag, (dummy) paramSize, returnCode.  Failure is fatal. */
    if (rcf == 0) {
	printf("TPM_Process_GetCapabilitySigned: Ordinal returnCode %08x %u\n",
	       returnCode, returnCode);
	rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
    }
    /* success response, append the rest of the parameters.  */
    if (rcf == 0) {
	if (returnCode == TPM_SUCCESS) {
	    /* checkpoint the beginning of the outParam's */
	    outParamStart = response->buffer_current - response->buffer;
	    /* return the version */
	    TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data));
	    returnCode = TPM_Version_Store(response, &version);
	}
	/* return the capability response size */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_Sbuffer_Append32(response, r1_length);
	}
	/* return the capability response */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_Sbuffer_Append(response, r1_buffer, r1_length);
	}
	/* return the signature */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_SizedBuffer_Store(response, &sig);
	    /* checkpoint the end of the outParam's */
	    outParamEnd = response->buffer_current - response->buffer;
	}
	/* digest the above the line output parameters */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_GetOutParamDigest(outParamDigest,	/* output */
					       auditStatus,	/* input audit status */
					       transportEncrypt,
					       tag,			
					       returnCode,
					       ordinal,		/* command ordinal */
					       response->buffer + outParamStart,	/* start */
					       outParamEnd - outParamStart);	/* length */
	}
	/* calculate and set the below the line parameters */
	if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	    returnCode = TPM_AuthParams_Set(response,
					    *hmacKey,	/* owner HMAC key */
					    auth_session_data,
					    outParamDigest,
					    nonceOdd,
					    continueAuthSession);
	}
	/* audit if required */
	if ((returnCode == TPM_SUCCESS) && auditStatus) {
	    returnCode = TPM_ProcessAudit(tpm_state,
					  transportEncrypt,
					  inParamDigest,
					  outParamDigest,
					  ordinal);
	}
	/* adjust the initial response */
	rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
    }
    /* if there was an error, or continueAuthSession is FALSE, terminate the session */
    if (((rcf != 0) ||
	 ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
	 !continueAuthSession) &&
	authHandleValid) {
	TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
    }
    /*
      cleanup
    */
    TPM_SizedBuffer_Delete(&subCap);	/* @1 */
    TPM_SizedBuffer_Delete(&resp);	/* @2 */
    TPM_SizedBuffer_Delete(&sig);	/* @3 */
    TPM_Sbuffer_Delete(&r1Response);	/* @4 */
    return rcf;
}

/* 7.2 TPM_SetCapability rev 96

   This command sets values in the TPM
*/

TPM_RESULT TPM_Process_SetCapability(tpm_state_t *tpm_state,
				     TPM_STORE_BUFFER *response,
				     TPM_TAG tag,
				     uint32_t paramSize,
				     TPM_COMMAND_CODE ordinal,
				     unsigned char *command,
				     TPM_TRANSPORT_INTERNAL *transportInternal)
{
    TPM_RESULT	rcf = 0;		/* fatal error precluding response */
    TPM_TAG	returnCode = 0;		/* command return code */

    /* input parameters */
    TPM_CAPABILITY_AREA capArea;	/* Partition of capabilities to be set */
    TPM_SIZED_BUFFER	subCap;		/* Further definition of information */
    TPM_SIZED_BUFFER	setValue;	/* The value to set */
    TPM_AUTHHANDLE	authHandle;	/* The authorization session handle used for owner
					   authentication. */
    TPM_NONCE		nonceOdd;	/* Nonce generated by system associated with authHandle */
    TPM_BOOL		continueAuthSession = TRUE;	/* The continue use flag for the
							   authorization session handle */
    TPM_AUTHDATA	ownerAuth;	/* Authorization. HMAC key: owner.usageAuth */

    /* processing parameters */
    unsigned char *	inParamStart;		/* starting point of inParam's */
    unsigned char *	inParamEnd;		/* ending point of inParam's */
    TPM_DIGEST		inParamDigest;
    TPM_BOOL		auditStatus;		/* audit the ordinal */
    TPM_BOOL		transportEncrypt;	/* wrapped in encrypted transport session */
    TPM_BOOL		authHandleValid = FALSE;
    TPM_AUTH_SESSION_DATA *auth_session_data;	/* session data for authHandle */
    TPM_SECRET		*hmacKey;
    uint16_t		subCap16;		/* the subCap as a uint16_t */
    uint32_t		subCap32;		/* the subCap as a uint32_t */
    TPM_BOOL		ownerAuthorized = FALSE;	/* TRUE if owner authorization validated */
    TPM_BOOL		presenceAuthorized = FALSE;	/* TRUE if physicalPresence validated */

    /* output parameters */
    uint32_t		outParamStart;		/* starting point of outParam's */
    uint32_t		outParamEnd;		/* ending point of outParam's */
    TPM_DIGEST		outParamDigest;

    printf("TPM_Process_SetCapability: Ordinal Entry\n");
    TPM_SizedBuffer_Init(&subCap);	/* freed @1 */
    TPM_SizedBuffer_Init(&setValue);	/* freed @2 */
    /*
      get inputs
    */
    /* save the starting point of inParam's for authorization and auditing */
    inParamStart = command;
    /* get capArea parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Load32(&capArea, &command, &paramSize);
    }
    /* get subCap parameter */
    if (returnCode == TPM_SUCCESS) {
	printf("TPM_Process_SetCapability: capArea %08x \n", capArea);
	returnCode = TPM_SizedBuffer_Load(&subCap, &command, &paramSize);
    }
    /* get setValue parameter */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_SizedBuffer_Load(&setValue , &command, &paramSize);
    }
    /* save the ending point of inParam's for authorization and auditing */
    inParamEnd = command;
    /* digest the input parameters */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_GetInParamDigest(inParamDigest,	/* output */
					  &auditStatus,		/* output */
					  &transportEncrypt,	/* output */
					  tpm_state,
					  tag,
					  ordinal,
					  inParamStart,
					  inParamEnd,
					  transportInternal);
    }
    /* check state */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN |
						     TPM_CHECK_NO_LOCKOUT));
    }
    /* check tag */
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_CheckRequestTag10(tag);
    }
    /* get the optional 'below the line' authorization parameters */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	ownerAuthorized = TRUE;
	returnCode = TPM_AuthParams_Get(&authHandle,
					&authHandleValid,
					nonceOdd,
					&continueAuthSession,
					ownerAuth,
					&command, &paramSize);
    }
    if (returnCode == TPM_SUCCESS) {
	if (paramSize != 0) {
	    printf("TPM_Process_SetCapability: Error, command has %u extra bytes\n",
		   paramSize);
	    returnCode = TPM_BAD_PARAM_SIZE;
	}
    }
    /* do not terminate sessions if the command did not parse correctly */
    if (returnCode != TPM_SUCCESS) {
	authHandleValid = FALSE;
    }
    /*
      Processing
    */
    /* 1. If tag = TPM_TAG_RQU_AUTH1_COMMAND, validate the command and parameters using ownerAuth,
       return TPM_AUTHFAIL on error */
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_AuthSessions_GetData(&auth_session_data,
					      &hmacKey,
					      tpm_state,
					      authHandle,
					      TPM_PID_NONE,
					      TPM_ET_OWNER,
					      ordinal,
					      NULL,
					      &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */
					      tpm_state->tpm_permanent_data.ownerAuth);	  /* OSAP */
    }
    if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	returnCode = TPM_Authdata_Check(tpm_state,
					*hmacKey,		/* owner HMAC key */
					inParamDigest,	
					auth_session_data,	/* authorization session */
					nonceOdd,		/* Nonce generated by system
								   associated with authHandle */
					continueAuthSession,
					ownerAuth);		/* Authorization digest for input */
    }
    if (returnCode == TPM_SUCCESS) {
	returnCode = TPM_Global_GetPhysicalPresence(&presenceAuthorized, tpm_state);
    }
    /* 2. The TPM validates the capArea and subCap indicators, including the ability to set value
       based on any set restrictions */
    /* 3. If the capArea and subCap indicators conform with one of the entries in the structure
       TPM_CAPABILITY_AREA (Values for TPM_SetCapability) */
    /* a. The TPM sets the relevant flag/data to the value of setValue parameter.  */
    /* 4. Else */
    /* a. Return the error code TPM_BAD_PARAMETER. */
    if (returnCode == TPM_SUCCESS) {
	/* subCap is often a uint16_t or uint32_t, create them now */
	TPM_GetSubCapInt(&subCap16, &subCap32, &subCap);
	returnCode = TPM_SetCapabilityCommon(tpm_state, ownerAuthorized, presenceAuthorized,
					     capArea, subCap16, subCap32, &subCap,
					     &setValue);
    }
    /*
      response
    */
    /* standard response: tag, (dummy) paramSize, returnCode.  Failure is fatal. */
    if (rcf == 0) {
	printf("TPM_Process_SetCapability: Ordinal returnCode %08x %u\n",
	       returnCode, returnCode);
	rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
    }
    /* success response, append the rest of the parameters.  */
    if (rcf == 0) {
	if (returnCode == TPM_SUCCESS) {
	    /* checkpoint the beginning of the outParam's */
	    outParamStart = response->buffer_current - response->buffer;
	    /* checkpoint the end of the outParam's */
	    outParamEnd = response->buffer_current - response->buffer;
	}
	/* digest the above the line output parameters */
	if (returnCode == TPM_SUCCESS) {
	    returnCode = TPM_GetOutParamDigest(outParamDigest,	/* output */
					       auditStatus,	/* input audit status */
					       transportEncrypt,
					       tag,			
					       returnCode,
					       ordinal,		/* command ordinal */
					       response->buffer + outParamStart,	/* start */
					       outParamEnd - outParamStart);	/* length */
	}
	/* calculate and set the below the line parameters */
	if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
	    returnCode = TPM_AuthParams_Set(response,
					    *hmacKey,		/* owner HMAC key */
					    auth_session_data,
					    outParamDigest,
					    nonceOdd,
					    continueAuthSession);
	}
	/* audit if required */
	if ((returnCode == TPM_SUCCESS) && auditStatus) {
	    returnCode = TPM_ProcessAudit(tpm_state,
					  transportEncrypt,
					  inParamDigest,
					  outParamDigest,
					  ordinal);
	}
	/* adjust the initial response */
	rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
    }
    /* if there was an error, terminate the session. */
    if (((rcf != 0) ||
	 ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
	 !continueAuthSession) &&
	authHandleValid) {
	TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
    }
    /*
      cleanup
    */
    TPM_SizedBuffer_Delete(&subCap);	/* @1 */
    TPM_SizedBuffer_Delete(&setValue);	/* @2 */
    return rcf;
}

/* TPM_SetCapabilityCommon() is common code for setting a capability from setValue
   
   NOTE: This function assumes that the caller has validated either owner authorization or physical
   presence!
*/

TPM_RESULT TPM_SetCapabilityCommon(tpm_state_t *tpm_state,
				   TPM_BOOL ownerAuthorized,
				   TPM_BOOL presenceAuthorized,
				   TPM_CAPABILITY_AREA capArea, 
				   uint16_t subCap16, 
				   uint32_t subCap32,
				   TPM_SIZED_BUFFER *subCap,
				   TPM_SIZED_BUFFER *setValue)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	valueBool;
    uint32_t	valueUint32 = 0;	/* start with illegal value */
    
    printf(" TPM_SetCapabilityCommon:\n");
    subCap16 = subCap16;			/* not used */
    subCap = subCap;				/* not used */
    if (rc == 0) {
	if ((capArea == TPM_SET_PERM_FLAGS) ||
	    (capArea == TPM_SET_STCLEAR_FLAGS) ||
	    (capArea == TPM_SET_STANY_FLAGS)) {
	    rc = TPM_SizedBuffer_GetBool(&valueBool, setValue);
	}
	else if (((capArea == TPM_SET_PERM_DATA) && (subCap32 != TPM_PD_DAAPROOF)) ||
		 (capArea == TPM_SET_STCLEAR_DATA)) {	/* deferredPhysicalPresence */
	    rc = TPM_SizedBuffer_GetUint32(&valueUint32, setValue);
	}
    }
    if (rc == 0) {
	switch (capArea) {
	  case TPM_SET_PERM_FLAGS:
	    rc = TPM_SetCapability_CapPermFlags(tpm_state, ownerAuthorized, presenceAuthorized,
						subCap32, valueBool);
	    break;
	  case TPM_SET_PERM_DATA:
	    rc = TPM_SetCapability_CapPermData(tpm_state, ownerAuthorized, presenceAuthorized,
					       subCap32, valueUint32);
	    break;
	  case TPM_SET_STCLEAR_FLAGS:
	    rc = TPM_SetCapability_CapStclearFlags(tpm_state, ownerAuthorized, presenceAuthorized,
						   subCap32, valueBool);
	    break;
	  case TPM_SET_STCLEAR_DATA:
	    rc = TPM_SetCapability_CapStclearData(tpm_state, ownerAuthorized, presenceAuthorized,
						  subCap32, valueUint32);
	    break;
	  case TPM_SET_STANY_FLAGS:
	    rc = TPM_SetCapability_CapStanyFlags(tpm_state, ownerAuthorized, presenceAuthorized,
						 subCap32, valueBool);
	    break;
	  case TPM_SET_STANY_DATA:
	    rc = TPM_SetCapability_CapStanyData(tpm_state, ownerAuthorized, presenceAuthorized,
						subCap32, setValue);
	    break;
	  case TPM_SET_VENDOR:
	    rc = TPM_SetCapability_CapVendor(tpm_state, ownerAuthorized, presenceAuthorized,
					     subCap32, setValue);
	    break;
	  default:
	    printf("TPM_SetCapabilityCommon: Error, unsupported capArea %08x", capArea);
	    rc = TPM_BAD_MODE;
	    break;
	}
    }
    return rc;
}

/* TPM_SetCapability_Flag() tests if the values are not already equal.	If they are not, 'flag' is
   set to 'value' and 'altered' is set TRUE.  Otherwise 'altered' is returned unchanged.

   The 'altered' flag is used by the caller to determine if an NVRAM write is required.
*/

void TPM_SetCapability_Flag(TPM_BOOL *altered,
			    TPM_BOOL *flag,
			    TPM_BOOL value)
{
    /* If the values are not already equal.  Can't use != since there are many values for TRUE. */
    if ((value && !*flag) ||
	(!value && *flag)) {
	*altered = TRUE;
	*flag = value;
    }
    return;
}

/* TPM_SetCapability_CapPermFlags() rev 100

   Sets TPM_PERMANENT_FLAGS values
*/
     
static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state,
						 TPM_BOOL ownerAuthorized,
						 TPM_BOOL presenceAuthorized,
						 uint32_t subCap32,
						 TPM_BOOL valueBool)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	altered = FALSE;	/* TRUE if the structure has been changed */
    
    printf(" TPM_SetCapability_CapPermFlags: valueBool %02x\n", valueBool);
    if (rc == 0) {						   
	switch (subCap32) {
	  case TPM_PF_DISABLE:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_DISABLE\n");
	    /* Owner authorization or physical presence
	       TPM_OwnerSetDisable
	       TPM_PhysicalEnable
	       TPM_PhysicalDisable
	    */
	    if (rc == 0) {
		if (!ownerAuthorized && !presenceAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, no authorization\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.disable),
				       valueBool);
	    }
	    break;
	  case TPM_PF_OWNERSHIP:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_OWNERSHIP\n");
	    /* No authorization. No ownerInstalled. Physical presence asserted
	       Not available when TPM deactivated or disabled
	       TPM_SetOwnerInstall
	    */
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_data.ownerInstalled) {
		    printf("TPM_SetCapability_CapPermFlags: Error, owner installed\n");
		    rc = TPM_OWNER_SET;
		}
	    }
	    if (rc == 0) {
		if (!presenceAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.ownership),
				       valueBool);
	    }
	    break;
	  case TPM_PF_DEACTIVATED:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_DEACTIVATED\n");
	    /* No authorization, physical presence assertion
	       Not available when TPM disabled
	       TPM_PhysicalSetDeactivated
	    */
	    if (rc == 0) {
		if (!presenceAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.deactivated),
				       valueBool);
	    }
	    break;
	  case TPM_PF_READPUBEK:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_READPUBEK\n");
	    /* Owner authorization
	       Not available when TPM deactivated or disabled
	    */
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.readPubek),
				       valueBool);
	    }
	    if (rc == 0) {
		printf("  TPM_SetCapability_CapPermFlags : readPubek %02x\n",
		       tpm_state->tpm_permanent_flags.readPubek);
	    }
	    break;
	  case TPM_PF_DISABLEOWNERCLEAR:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEOWNERCLEAR\n");
	    /* Owner authorization. Can only set to TRUE, FALSE invalid value. 
	       After being set only ForceClear resets back to FALSE.
	       Not available when TPM deactivated or disabled
	       TPM_DisableOwnerClear */
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (!valueBool) {
		    printf("TPM_SetCapability_CapPermFlags: Error, cannot set FALSE\n");
		    rc = TPM_BAD_PARAMETER;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.disableOwnerClear),
				       valueBool);
	    }
	    break;
	  case TPM_PF_ALLOWMAINTENANCE:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_ALLOWMAINTENANCE\n");
	    /* Owner authorization. Can only set to FALSE, TRUE invalid value. 
	       After being set only changing TPM owner resets back to TRUE
	       Not available when TPM deactivated or disabled
	       TPM_KillMaintenanceFeature
	    */
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (valueBool) {
		    printf("TPM_SetCapability_CapPermFlags: Error, cannot set TRUE\n");
		    rc = TPM_BAD_PARAMETER;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.allowMaintenance),
				       valueBool);
	    }
	    break;
	  case TPM_PF_READSRKPUB:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_READSRKPUB\n");
	    /* Owner Authorization
	       Not available when TPM deactivated or disabled
	       TPM_SetCapability
	    */
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermFlags: Error, disable is TRUE\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermFlags: Error, deactivated is TRUE\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.readSRKPub),
				       valueBool);
	    }
	    break;
	  case TPM_PF_TPMESTABLISHED:
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_TPMESTABLISHED\n");
	    /* Locality 3 or locality 4
	       Can only set to FALSE
	       TPM_ResetEstablishmentBit
	    */
	    if (rc == 0) {
		rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR,  /* BYTE bitmap */
					tpm_state->tpm_stany_flags.localityModifier);
	    }
	    if (rc == 0) {
		if (valueBool) {
		    printf("TPM_SetCapability_CapPermFlags: Error, can only set to FALSE\n");
		    rc = TPM_BAD_PARAMETER;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.tpmEstablished),
				       valueBool);
	    }
	    break;
#if  (TPM_REVISION >= 103)	/* added for rev 103 */
	  case TPM_PF_DISABLEFULLDALOGICINFO:
	    /* Owner Authorization
	       TPM_SetCapability
	    */
	    printf("  TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEFULLDALOGICINFO\n");
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		TPM_SetCapability_Flag(&altered,
				       &(tpm_state->tpm_permanent_flags.disableFullDALogicInfo),
				       valueBool);
	    }
	    break;
#endif
	  case TPM_PF_PHYSICALPRESENCELIFETIMELOCK:
	  case TPM_PF_PHYSICALPRESENCEHWENABLE:
	  case TPM_PF_PHYSICALPRESENCECMDENABLE:
	  case TPM_PF_CEKPUSED:
	  case TPM_PF_TPMPOST:
	  case TPM_PF_TPMPOSTLOCK:
	  case TPM_PF_FIPS:
	  case TPM_PF_OPERATOR:
	  case TPM_PF_ENABLEREVOKEEK:
	  case TPM_PF_NV_LOCKED:
	  case TPM_PF_MAINTENANCEDONE:
	  default:
	    printf("TPM_SetCapability_CapPermFlags: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}
    }
    rc = TPM_PermanentAll_NVStore(tpm_state,
				  altered,
				  rc);
    return rc;
}

/* TPM_SetCapability_CapPermData() rev 105

   Sets TPM_PERMANENT_DATA values
*/
     
static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state,
						TPM_BOOL ownerAuthorized,
						TPM_BOOL presenceAuthorized,
						uint32_t subCap32,
						uint32_t valueUint32)
{
    TPM_RESULT	rc = 0;
    TPM_BOOL	writeAllNV = FALSE;	/* TRUE if the structure has been changed */
    
    printf(" TPM_SetCapability_CapPermData:\n");
    presenceAuthorized = presenceAuthorized;			/* not used */
    if (rc == 0) {						   
	switch (subCap32) {
	  case TPM_PD_RESTRICTDELEGATE:
	    printf("  TPM_SetCapability_CapPermData: TPM_PD_RESTRICTDELEGATE\n");
	    /* Owner authorization.  Not available when TPM deactivated or disabled */
	    /* TPM_CMK_SetRestrictions */
	    if (rc == 0) {
		if (!ownerAuthorized) {
		    printf("TPM_SetCapability_CapPermData: Error, not owner authorized\n");
		    rc = TPM_AUTHFAIL;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapPermData: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapPermData: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_data.restrictDelegate != valueUint32) {
		    tpm_state->tpm_permanent_data.restrictDelegate = valueUint32;
		    writeAllNV = TRUE;
		}
	    }
	    break;
	  case TPM_PD_DAAPROOF:
	    /* TPM_PD_DAAPROOF This capability has no value.  When specified by TPM_SetCapability, a
	       new daaProof, tpmDAASeed, and daaBlobKey are generated. */
		rc = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data));
		writeAllNV = TRUE;
	    break;
	  case TPM_PD_REVMAJOR:
	  case TPM_PD_REVMINOR:
	  case TPM_PD_TPMPROOF:
	  case TPM_PD_OWNERAUTH:
	  case TPM_PD_OPERATORAUTH:
	  case TPM_PD_MANUMAINTPUB:
	  case TPM_PD_ENDORSEMENTKEY:
	  case TPM_PD_SRK:
	  case TPM_PD_DELEGATEKEY:
	  case TPM_PD_CONTEXTKEY:
	  case TPM_PD_AUDITMONOTONICCOUNTER:
	  case TPM_PD_MONOTONICCOUNTER:
	  case TPM_PD_PCRATTRIB:
	  case TPM_PD_ORDINALAUDITSTATUS:
	  case TPM_PD_AUTHDIR:
	  case TPM_PD_RNGSTATE:
	  case TPM_PD_FAMILYTABLE:
	  case TPM_DELEGATETABLE:
	  case TPM_PD_EKRESET:
	  case TPM_PD_LASTFAMILYID:
	  case TPM_PD_NOOWNERNVWRITE:
	  case TPM_PD_TPMDAASEED:
	  default:
	    printf("TPM_SetCapability_CapPermData: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}
    }
    rc = TPM_PermanentAll_NVStore(tpm_state,
				  writeAllNV,
				  rc);
    return rc;
}

/* TPM_SetCapability_CapStclearFlags() rev 85

   Sets TPM_STCLEAR_FLAGS values
*/
     
static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state,
						    TPM_BOOL ownerAuthorized,
						    TPM_BOOL presenceAuthorized,
						    uint32_t subCap32,
						    TPM_BOOL valueBool)
{
    TPM_RESULT			rc = 0;

    printf(" TPM_SetCapability_CapStclearFlags: valueBool %02x\n", valueBool);
    ownerAuthorized = ownerAuthorized;		/* not used */
    presenceAuthorized = presenceAuthorized;	/* not used */
    if (rc == 0) {						   
	switch (subCap32) {
	  case TPM_SF_DISABLEFORCECLEAR:
	    printf("  TPM_SetCapability_CapStclearFlags: TPM_SF_DISABLEFORCECLEAR\n");
	    /* Not available when TPM deactivated or disabled */
	    /* TPM_DisableForceClear */
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapStclearFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapStclearFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    /* Can only set to TRUE */
	    if (rc == 0) {
		if (!valueBool) {
		    printf("TPM_SetCapability_CapStclearFlags: Error, cannot set FALSE\n");
		    rc = TPM_BAD_PARAMETER;
		}
	    }
	    if (rc == 0) {
		tpm_state->tpm_stclear_flags.disableForceClear = TRUE;
	    }
	    break;
	  case TPM_SF_DEACTIVATED:
	  case TPM_SF_PHYSICALPRESENCE:
	  case TPM_SF_PHYSICALPRESENCELOCK:
	  case TPM_SF_BGLOBALLOCK:
	  default:
	    printf("TPM_SetCapability_CapStclearFlags: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}
    }
    return rc;
}

/* TPM_SetCapability_CapStclearData() rev 100

   Sets TPM_STCLEAR_DATA values
*/
     
static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state,
						   TPM_BOOL ownerAuthorized,
						   TPM_BOOL presenceAuthorized,
						   uint32_t subCap32,
						   uint32_t valueUint32)
{
    TPM_RESULT			rc = 0;
#if  (TPM_REVISION < 103)	/* added for rev 103 */
    tpm_state = tpm_state;	/* to quiet the compiler */
    presenceAuthorized = presenceAuthorized;
    valueUint32 = valueUint32;
#endif

    printf(" TPM_SetCapability_CapStclearData:\n");
    ownerAuthorized = ownerAuthorized;		/* not used */
    if (rc == 0) {						   
	switch (subCap32) {
#if  (TPM_REVISION >= 103)	/* added for rev 103 */
	  case TPM_SD_DEFERREDPHYSICALPRESENCE:
	    printf("  TPM_SetCapability_CapStclearData: TPM_SD_DEFERREDPHYSICALPRESENCE\n");
	    /* Can only set to TRUE if PhysicalPresence is asserted.  Can set to FALSE at any
	       time. */
	    /* 1. If physical presence is not asserted */
	    /* a. If TPM_SetCapability -> setValue has a bit set that is not already set in
	       TPM_STCLEAR_DATA -> deferredPhysicalPresence, return TPM_BAD_PRESENCE. */
	    if (rc == 0) {
		if (!presenceAuthorized) {
		    if (~(tpm_state->tpm_stclear_data.deferredPhysicalPresence) & valueUint32) {
			printf("TPM_SetCapability_CapStclearData: "
			       "Error, no physicalPresence and deferredPhysicalPresence %08x\n",
			       tpm_state->tpm_stclear_data.deferredPhysicalPresence);
			rc = TPM_BAD_PRESENCE;
		    }
		}
	    }
	    /* 2.Set TPM_STCLEAR_DATA -> deferredPhysicalPresence to TPM_SetCapability -> setValue.
	    */
	    if (rc == 0) {
		printf("   TPM_SetCapability_CapStclearData: deferredPhysicalPresence now %08x\n",
		       valueUint32);
		tpm_state->tpm_stclear_data.deferredPhysicalPresence = valueUint32;
	    }
	    break;
#endif
	  case TPM_SD_CONTEXTNONCEKEY:
	  case TPM_SD_COUNTID:
	  case TPM_SD_OWNERREFERENCE:
	  case TPM_SD_DISABLERESETLOCK:
	  case TPM_SD_PCR:
	  default:
	    printf("TPM_SetCapability_CapStclearData: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}
    }
    return rc;
}

/* TPM_SetCapability_CapStanyFlags() rev 85

   Sets TPM_STANY_FLAGS values
*/
     
static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state,
						  TPM_BOOL ownerAuthorized,
						  TPM_BOOL presenceAuthorized,
						  uint32_t subCap32,
						  TPM_BOOL valueBool)
{
    TPM_RESULT			rc = 0;

    printf(" TPM_SetCapability_CapStanyFlags:\n");
    ownerAuthorized = ownerAuthorized;			/* not used */
    presenceAuthorized = presenceAuthorized;		/* not used */
    if (rc == 0) {						   
	switch (subCap32) {
	  case TPM_AF_TOSPRESENT:
	    printf("  TPM_SetCapability_CapStanyFlags: TPM_AF_TOSPRESENT\n");
	    /* locality 3 or 4 */
	    /* Not available when TPM deactivated or disabled */
	    if (rc == 0) {
		rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR,
					tpm_state->tpm_stany_flags.localityModifier);
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_permanent_flags.disable) {
		    printf("TPM_SetCapability_CapStanyFlags: Error, disabled\n");
		    rc = TPM_DISABLED;
		}
	    }
	    if (rc == 0) {
		if (tpm_state->tpm_stclear_flags.deactivated) {
		    printf("TPM_SetCapability_CapStanyFlags: Error, deactivated\n");
		    rc = TPM_DEACTIVATED;
		}
	    }
	    /* can only be set to FALSE */
	    if (rc == 0) {
		if (valueBool) {
		    printf("TPM_SetCapability_CapStanyFlags: Error, cannot set TRUE\n");
		    rc = TPM_BAD_PARAMETER;
		}
	    }
	    if (rc == 0) {
		tpm_state->tpm_stany_flags.TOSPresent = FALSE;
	    }
	    break;
	  case TPM_AF_POSTINITIALISE:
	  case TPM_AF_LOCALITYMODIFIER:
	  case TPM_AF_TRANSPORTEXCLUSIVE:
	  default:
	    printf("TPM_SetCapability_CapStanyFlags: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}
    }
    return rc;
}

/* TPM_SetCapability_CapStanyData() rev 85

   Sets TPM_STANY_DATA values
*/

static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state,
						 TPM_BOOL ownerAuthorized,
						 TPM_BOOL presenceAuthorized,
						 uint32_t subCap32,
						 TPM_SIZED_BUFFER *setValue)
{
    TPM_RESULT			rc = 0;

    printf(" TPM_SetCapability_CapStanyData:\n");
    tpm_state = tpm_state;			/* not used */
    ownerAuthorized = ownerAuthorized;		/* not used */
    presenceAuthorized = presenceAuthorized;	/* not used */
    setValue = setValue;			/* not used */
    if (rc == 0) {						   
	switch (subCap32) {
	  case TPM_AD_CONTEXTNONCESESSION:
	  case TPM_AD_AUDITDIGEST:
	  case TPM_AD_CURRENTTICKS:
	  case TPM_AD_CONTEXTCOUNT:
	  case TPM_AD_CONTEXTLIST:
	  case TPM_AD_SESSIONS:
	  default:
	    printf("TPM_SetCapability_CapStanyData: Error, bad subCap32 %u\n",
		   subCap32);
	    rc = TPM_BAD_PARAMETER;
	}				
    }
    return rc;
}

/* These are subCaps to TPM_SetCapability -> TPM_SET_VENDOR capArea, the vendor specific area.
*/

static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state,
					      TPM_BOOL ownerAuthorized,
					      TPM_BOOL presenceAuthorized,
					      uint32_t subCap32,
					      TPM_SIZED_BUFFER *setValue)
{
    TPM_RESULT			rc = 0;
    
    printf(" TPM_SetCapability_CapVendor:\n");
    ownerAuthorized = ownerAuthorized;		/* not used */
    presenceAuthorized = presenceAuthorized;	/* not used */
    setValue = setValue;
    /* make temporary copies so the setValue is not touched */
    if (rc == 0) {
	switch(subCap32) {
	  default:
	    printf("TPM_SetCapability_CapVendor: Error, unsupported subCap %08x\n", subCap32);
	    tpm_state = tpm_state;			/* not used */
	    rc = TPM_BAD_PARAMETER;
	    break;

	}
    }
    return rc;
}
