//**********************************************************************;
// Copyright (c) 2015, Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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.
//**********************************************************************;

//
// tpmclient.cpp : Defines the entry point for the console test application.
//

#ifdef NO_RM_TESTS
#include "tpmclient_wo_rm.h"
#else
#define SESSIONS_COUNT 5
#endif

#ifndef UNICODE
#define UNICODE 1
#endif

#ifdef _WIN32
// link with Ws2_32.lib
#pragma comment(lib,"Ws2_32.lib")

#include <winsock2.h>
#include <ws2tcpip.h>
#else
#define sprintf_s   snprintf
#define sscanf_s    sscanf
#endif

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>   // Needed for _wtoi
#include <string.h>

#include "sapi/tpm20.h"
#include "../integration/sapi-util.h"
#include "sample.h"
#include "tpmclient.h"
#include "tcti_util.h"

// This is done to allow the tests to access fields
// in the sysContext structure that are needed for
// special test cases.
//
// ATTENTION:  Normal applications should NEVER do this!!
//
#include "sysapi_util.h"

#include "tcti/tcti_device.h"
#include "tcti/tcti_socket.h"
#include "syscontext.h"
#include "common/debug.h"

//
// TPM indices and sizes
//
#define NV_AUX_INDEX_SIZE     96
#define NV_PS_INDEX_SIZE      34
#define NV_PO_INDEX_SIZE      34

#define INDEX_AUX                       0x01800003 // NV Storage
#define INDEX_LCP_OWN                   0x01400001 // Launch Policy Owner
#define INDEX_LCP_SUP                   0x01800001 // Launch Policy Default (Supplier)
#define TPM20_INDEX_TEST1               0x01500015
#define TPM20_INDEX_TEST2               0x01500016
#define TPM20_INDEX_PASSWORD_TEST       0x01500020


#define SET_PCR_SELECT_BIT( pcrSelection, pcr ) \
                                                (pcrSelection).pcrSelect[( (pcr)/8 )] |= ( 1 << ( (pcr) % 8) );

#define CLEAR_PCR_SELECT_BITS( pcrSelection ) \
                                              (pcrSelection).pcrSelect[0] = 0; \
                                              (pcrSelection).pcrSelect[1] = 0; \
                                              (pcrSelection).pcrSelect[2] = 0;

#define SET_PCR_SELECT_SIZE( pcrSelection, size ) \
                                                  (pcrSelection).sizeofSelect = size;

TPM_CC currentCommandCode;
TPM_CC *currentCommandCodePtr = &currentCommandCode;

#define errorStringSize 200
char errorString[errorStringSize];

UINT8 simulator = 1;

UINT32 tpmMaxResponseLen = TPMBUF_LEN;

UINT8 resMgrInitialized = 0;

UINT8 pcrAfterExtend[20];
TPM_HANDLE loadedRsaKeyHandle;
TPM_HANDLE loadedSha1KeyHandle;

TPM2B_AUTH loadedSha1KeyAuth;

TPM_HANDLE handle1024, handle2048sha1, handle2048rsa;

UINT8 indent = 0;

TSS2_SYS_CONTEXT *sysContext;

TCTI_SOCKET_CONF rmInterfaceConfig = {
    DEFAULT_HOSTNAME,
    DEFAULT_SIMULATOR_TPM_PORT,
    DebugPrintfCallback,
    DebugPrintBufferCallback,
    NULL
};

TSS2_TCTI_CONTEXT *resMgrTctiContext = 0;
TSS2_ABI_VERSION abiVersion = { TSSWG_INTEROP, TSS_SAPI_FIRST_FAMILY, TSS_SAPI_FIRST_LEVEL, TSS_SAPI_FIRST_VERSION };

UINT32 tpmSpecVersion = 0;
UINT32 tpmManufacturer = 0;

#define MSFT_MANUFACTURER_ID 0x4d534654
#define IBM_MANUFACTURER_ID 0x49424d20

//
// These are helper functions that are called through function pointers so that
// they could be swapped easily to point to different functions.
//
// Currently they are set to functions that use the TPM to perform the function, but SW-only
// implementations could be substituted as well.
//
UINT32 ( *ComputeSessionHmacPtr )(
    TSS2_SYS_CONTEXT *sysContext,
    TPMS_AUTH_COMMAND *cmdAuth, // Pointer to session input struct
    TPM_HANDLE entityHandle,             // Used to determine if we're accessing a different
    // resource than the bound resoure.
    TPM_RC responseCode,                 // Response code for the command, 0xffff for "none" is
    // used to indicate that no response code is present
    // (used for calculating command HMACs vs response HMACs).
    TPM_HANDLE handle1,                  // First handle == 0xff000000 indicates no handle
    TPM_HANDLE handle2,                  // Second handle == 0xff000000 indicates no handle
    TPMA_SESSION sessionAttributes,      // Current session attributes
    TPM2B_DIGEST *result,                // Where the result hash is saved.
    TPM_RC sessionCmdRval
    ) = TpmComputeSessionHmac;

TPM_RC ( *GetSessionAlgIdPtr )( TPMI_SH_AUTH_SESSION authHandle, TPMI_ALG_HASH *sessionAlgId ) = GetSessionAlgId;

TPM_RC ( *CalcPHash )( TSS2_SYS_CONTEXT *sysContext,TPM_HANDLE handle1, TPM_HANDLE handle2, TPMI_ALG_HASH authHash,
    TPM_RC responseCode, TPM2B_DIGEST *pHash ) = TpmCalcPHash;

UINT32 (*HmacFunctionPtr)( TPM_ALG_ID hashAlg, TPM2B *key,TPM2B **bufferList, TPM2B_DIGEST *result ) = TpmHmac;

UINT32 (*HashFunctionPtr)( TPMI_ALG_HASH hashAlg, UINT16 size, BYTE *data, TPM2B_DIGEST *result ) = TpmHash;

UINT32 (*HandleToNameFunctionPtr)( TPM_HANDLE handle, TPM2B_NAME *name ) = TpmHandleToName;

TPMI_SH_AUTH_SESSION StartPolicySession();

TPMI_SH_AUTH_SESSION InitNvAuxPolicySession();

TPM_RC CompareTPM2B( TPM2B *buffer1, TPM2B *buffer2 )
{
    if( buffer1->size != buffer2->size )
        return TPM_RC_FAILURE;
    for( int i = 0; i < buffer1->size; i++ )
    {
        if( buffer1->buffer[0] != buffer2->buffer[0] )
            return TPM_RC_FAILURE;
    }
    return TPM_RC_SUCCESS;
}

void PrintSizedBuffer( TPM2B *sizedBuffer )
{
    int i;

    for( i = 0; i < sizedBuffer->size; i++ )
    {
        DebugPrintf( NO_PREFIX, "%2.2x ", sizedBuffer->buffer[i] );

        if( ( (i+1) % 16 ) == 0 )
        {
            DebugPrintf( NO_PREFIX, "\n" );
        }
    }
    DebugPrintf( NO_PREFIX, "\n" );
}

#define LEVEL_STRING_SIZE 50

void ErrorHandler( UINT32 rval )
{
    UINT32 errorLevel = rval & TSS2_ERROR_LEVEL_MASK;
    char levelString[LEVEL_STRING_SIZE + 1];

    switch( errorLevel )
    {
        case TSS2_TPM_ERROR_LEVEL:
            strncpy( levelString, "TPM", LEVEL_STRING_SIZE );
            break;
        case TSS2_APP_ERROR_LEVEL:
            strncpy( levelString, "Application", LEVEL_STRING_SIZE );
            break;
        case TSS2_SYS_ERROR_LEVEL:
            strncpy( levelString, "System API", LEVEL_STRING_SIZE );
            break;
        case TSS2_SYS_PART2_ERROR_LEVEL:
            strncpy( levelString, "System API TPM encoded", LEVEL_STRING_SIZE );
            break;
        case TSS2_TCTI_ERROR_LEVEL:
            strncpy( levelString, "TCTI", LEVEL_STRING_SIZE );
            break;
        case TSS2_RESMGRTPM_ERROR_LEVEL:
            strncpy( levelString, "Resource Mgr TPM encoded", LEVEL_STRING_SIZE );
            break;
        case TSS2_RESMGR_ERROR_LEVEL:
            strncpy( levelString, "Resource Mgr", LEVEL_STRING_SIZE );
            break;
        case TSS2_DRIVER_ERROR_LEVEL:
            strncpy( levelString, "Driver", LEVEL_STRING_SIZE );
            break;
        default:
            strncpy( levelString, "Unknown Level", LEVEL_STRING_SIZE );
            break;
	}

    sprintf_s( errorString, errorStringSize, "%s Error: 0x%x\n", levelString, rval );
}

void Cleanup()
{
    fflush( stdout );

    if( resMgrTctiContext != 0 )
    {
        PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
        TeardownTctiContext( &resMgrTctiContext );
    }

#ifdef _WIN32
    WSACleanup();
#endif
    exit(1);
}

void InitSysContextFailure()
{
    DebugPrintf( NO_PREFIX, "InitSysContext failed, exiting...\n" );
    Cleanup();
}

void Delay( UINT16 delay)
{
    volatile UINT32 i, j;

    for( j = 0; j < delay; j++ )
    {
        for( i = 0; i < 10000000; i++ )
            ;
    }
}

#define CheckPassed(rval) {				\
    							\
    DebugPrintf( NO_PREFIX, "\tpassing case:  " );			\
    if ( rval != TPM_RC_SUCCESS) {					\
      ErrorHandler( rval);						\
      DebugPrintf( NO_PREFIX, "\tFAILED!  %s (%s@%u)\n",		\
		   errorString, __FUNCTION__, __LINE__ );		\
      Cleanup();							\
    } else {								\
      DebugPrintf( NO_PREFIX, "\tPASSED! (%s@%u)\n",			\
		   __FUNCTION__, __LINE__);				\
    }									\
    									\
    Delay(0);							\
  }

TPMS_AUTH_COMMAND nullSessionData;
TPMS_AUTH_RESPONSE nullSessionDataOut;
TPMS_AUTH_COMMAND *nullSessionDataArray[1] = { &nullSessionData };
TPMS_AUTH_RESPONSE *nullSessionDataOutArray[1] = { &nullSessionDataOut };
TSS2_SYS_CMD_AUTHS nullSessionsData = { 1, &nullSessionDataArray[0] };
TSS2_SYS_RSP_AUTHS nullSessionsDataOut = { 1, &nullSessionDataOutArray[0] };
TPM2B_NONCE nullSessionNonce, nullSessionNonceOut;
TPM2B_AUTH nullSessionHmac;

#define CheckFailed(rval, expectedTpmErrorCode) {			\
    DebugPrintf( NO_PREFIX, "\tfailing case:");				\
    if ( rval != expectedTpmErrorCode) {				\
      ErrorHandler( rval);						\
      DebugPrintf( NO_PREFIX, "\tFAILED!  Ret code s/b: 0x%x, but was: 0x%x (%s@%u)\n", \
		   expectedTpmErrorCode, rval, __FUNCTION__, __LINE__ ); \
      Cleanup();							\
    }	else {								\
      DebugPrintf( NO_PREFIX, "\tPASSED! (%s@%u)\n",			\
		   __FUNCTION__, __LINE__);				\
    }									\
    Delay(0);							\
  }


TSS2_RC TpmReset()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;

    rval = (TSS2_RC)PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
    if( rval == TSS2_RC_SUCCESS )
    {
        rval = (TSS2_RC)PlatformCommand( resMgrTctiContext, MS_SIM_POWER_ON );
    }
    return rval;
}

void GetTpmVersion()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TPMS_CAPABILITY_DATA capabilityData;

    rval = Tss2_Sys_GetCapability( sysContext, 0,
            TPM_CAP_TPM_PROPERTIES, TPM_PT_REVISION,
            1, 0, &capabilityData, 0 );
    CheckPassed( rval );

    if( capabilityData.data.tpmProperties.count == 1 &&
            (capabilityData.data.tpmProperties.tpmProperty[0].property == TPM_PT_REVISION) )
    {
        tpmSpecVersion = capabilityData.data.tpmProperties.tpmProperty[0].value;
        DebugPrintf( NO_PREFIX, "TPM spec version:  %d\n", tpmSpecVersion );
    }
    else
    {
        DebugPrintf( NO_PREFIX, "Failed to get TPM spec version!!\n" );
        Cleanup();
    }
}

void GetTpmManufacturer()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TPMS_CAPABILITY_DATA capabilityData;

    rval = Tss2_Sys_GetCapability( sysContext, 0,
            TPM_CAP_TPM_PROPERTIES, TPM_PT_MANUFACTURER,
            1, 0, &capabilityData, 0 );
    CheckPassed( rval );

    if( capabilityData.data.tpmProperties.count == 1 &&
            (capabilityData.data.tpmProperties.tpmProperty[0].property == TPM_PT_MANUFACTURER ) )
    {
        tpmManufacturer = capabilityData.data.tpmProperties.tpmProperty[0].value;
    }
    else
    {
        DebugPrintf( NO_PREFIX, "Failed to get TPM manufacturer!!\n" );
        Cleanup();
    }
}

void TestDictionaryAttackLockReset()
{
    UINT32 rval;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nDICTIONARY ATTACK LOCK RESET TEST  :\n" );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    rval = Tss2_Sys_DictionaryAttackLockReset ( sysContext, TPM_RH_LOCKOUT, &sessionsData, &sessionsDataOut );
    CheckPassed( rval );
}

TSS2_RC StartPolicySession( TPMI_SH_AUTH_SESSION *sessionHandle )
{
    UINT8 i;
    TPM2B_NONCE nonceCaller, nonceTpm;
    TPM2B_ENCRYPTED_SECRET salt;
    TPMT_SYM_DEF symmetric;
    UINT16 digestSize;
    UINT32 rval;

    digestSize = GetDigestSize( TPM_ALG_SHA1 );
    nonceCaller.t.size = digestSize;
    for( i = 0; i < nonceCaller.t.size; i++ )
        nonceCaller.t.buffer[i] = 0;

    salt.t.size = 0;
    symmetric.algorithm = TPM_ALG_NULL;

    // Create policy session
    INIT_SIMPLE_TPM2B_SIZE( nonceTpm );
    rval = Tss2_Sys_StartAuthSession ( sysContext, TPM_RH_NULL, TPM_RH_NULL, 0, &nonceCaller, &salt,
            TPM_SE_POLICY, &symmetric, TPM_ALG_SHA1, sessionHandle, &nonceTpm, 0 );
    return( rval );
}

void TestTpmStartup()
{
    UINT32 rval;

    DebugPrintf( NO_PREFIX, "\nSTARTUP TESTS:\n" );

    //
    // First test the one-call interface.
    //

    // First must do TPM reset.
    rval = TpmReset();
    CheckPassed(rval);

    // This one should pass.
    rval = Tss2_Sys_Startup( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval);

    // This one should fail.
    rval = Tss2_Sys_Startup( sysContext, TPM_SU_CLEAR );
    CheckFailed( rval, TPM_RC_INITIALIZE );


    // Cycle power using simulator interface.
    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
    CheckPassed( rval );
    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_ON );
    CheckPassed( rval );


    //
    // Now test the syncronous, non-one-call interface.
    //
    rval = Tss2_Sys_Startup_Prepare( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval);

    // Execute the command syncronously.
    rval = Tss2_Sys_Execute( sysContext );
    CheckPassed( rval );

    // Cycle power using simulator interface.
    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
    CheckPassed( rval );
    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_ON );
    CheckPassed( rval );


    //
    // Now test the asyncronous, non-one-call interface.
    //
    rval = Tss2_Sys_Startup_Prepare( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval);

    // Execute the command asyncronously.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed(rval);

    // Get the command response. Wait a maximum of 20ms
    // for response.
    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckPassed(rval);
}

void TestSapiApis()
{
    UINT32 rval;
    TPM2B_MAX_BUFFER    outData = { { MAX_DIGEST_BUFFER, } };
    TPM_RC              testResult;
    TSS2_SYS_CONTEXT    *testSysContext;
    TPM2B_PUBLIC        outPublic;
    TPM2B_NAME          name;
    TPM2B_NAME          qualifiedName;
    UINT8               commandCode[4];
    size_t				rpBufferUsedSize;
	const uint8_t 		*rpBuffer;
	const uint8_t 		goodRpBuffer[] = { 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
                                           0x01, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00,
										   0x40 };
    TPMI_YES_NO         moreData;
    TPMS_CAPABILITY_DATA	capabilityData;
    int                 rpBufferError = 0;
    unsigned int        i;
    UINT32              savedRspSize;

    DebugPrintf( NO_PREFIX, "\nSAPI API TESTS:\n" );

    //
    // First test the one-call interface.
    //
    rval = Tss2_Sys_GetTestResult( sysContext, 0, &outData, &testResult, 0 );
    CheckPassed(rval); // #1

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #2

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #3

    //
    // Now test the syncronous, non-one-call interface.
    //
    rval = Tss2_Sys_GetTestResult_Prepare( sysContext );
    CheckPassed(rval); // #4

    // Check for BAD_REFERENCE error.
    rval = Tss2_Sys_Execute( 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #5

    // Execute the command syncronously.
    rval = Tss2_Sys_Execute( sysContext );
    CheckPassed(rval); // #6

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #7

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #8

    // Get the command results
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    CheckPassed(rval); // #9

    //
    // Now test the asyncronous, non-one-call interface.
    //
    rval = Tss2_Sys_GetTestResult_Prepare( sysContext );
    CheckPassed(rval); // #10

    // Test XXXX_Complete for bad sequence:  after _Prepare
    // and before ExecuteFinish
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #11

    // Check for BAD_REFERENCE error.
    rval = Tss2_Sys_ExecuteAsync( 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #12

    // Test ExecuteFinish for BAD_SEQUENCE
    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #13

    // Execute the command asyncronously.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed(rval); // #14

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #15

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #16

    // Test ExecuteFinish for BAD_REFERENCE
    rval = Tss2_Sys_ExecuteFinish( 0, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #17

    // Test XXXX_Complete for bad sequence:  after _Prepare
    // and before ExecuteFinish
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #18

    // Get the command response. Wait a maximum of 20ms
    // for response.
    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckPassed(rval); // #19

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #20

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #21

    // Check for BAD_SEQUENCE error.
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #22

    // Test _Complete for bad reference cases.
    rval = Tss2_Sys_GetTestResult_Complete( 0, &outData, &testResult );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #23

    // Get the command results
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    CheckPassed(rval); // #24

    testSysContext = InitSysContext( 0,  resMgrTctiContext, &abiVersion );
    if( testSysContext == 0 )
    {
        InitSysContextFailure();
    }

    // Test GetCommandCode for bad sequence
    rval = Tss2_Sys_GetCommandCode( testSysContext, &commandCode );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #25

    rval = Tss2_Sys_GetRpBuffer( testSysContext, &rpBufferUsedSize, &rpBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #26

    TeardownSysContext( &testSysContext );

    rval = Tss2_Sys_ReadPublic_Prepare( sysContext, handle2048rsa );
    CheckPassed(rval); // #27

    // Execute the command syncronously.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval ); // #28

    // Test _Complete for bad sequence case when ExecuteFinish has never
    // been done on a context.
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_ReadPublic_Complete( sysContext, &outPublic, &name, &qualifiedName );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #29

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckPassed( rval ); // #30

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #31

    rval = Tss2_Sys_ReadPublic_Prepare( sysContext, handle2048rsa );
    CheckPassed(rval); // #32

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #33

    rval = Tss2_Sys_ReadPublic_Prepare( sysContext, handle2048rsa );
    CheckPassed(rval); // #34

    // Execute the command syncronously.
    rval = Tss2_Sys_Execute( sysContext );
    CheckPassed( rval ); // #35

	outPublic.t.size = name.t.size = qualifiedName.t.size = 0;
	rval = Tss2_Sys_ReadPublic( sysContext, handle2048rsa, 0,
            &outPublic, 0, 0, 0 );
    CheckPassed( rval ); // #36

    // Check case of ExecuteFinish receving TPM error code.
    // Subsequent _Complete call should fail with SEQUENCE error.
    rval = TpmReset();
    CheckPassed(rval); // #37

    rval = Tss2_Sys_GetCapability_Prepare( sysContext,
            TPM_CAP_TPM_PROPERTIES, TPM_PT_ACTIVE_SESSIONS_MAX,
            1 );
    CheckPassed(rval); // #38

    // Execute the command asyncronously.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed(rval); // #39

    // Get the command response. Wait a maximum of 20ms
    // for response.
    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TPM_RC_INITIALIZE ); // #40

    // Test _Complete for case when ExecuteFinish had an error.
    rval = Tss2_Sys_GetCapability_Complete( sysContext, 0, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #41

    rval = Tss2_Sys_Startup( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval); // #42

    rval = Tss2_Sys_GetRpBuffer( 0, &rpBufferUsedSize, &rpBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #43

    rval = Tss2_Sys_GetRpBuffer( sysContext, 0, &rpBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #44

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #45

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, &rpBuffer );
    CheckPassed( rval ); // #46

    // Now test case for ExecuteFinish where TPM returns
    // an error.  ExecuteFinish should return same error
    // as TPM.
    rval = Tss2_Sys_Startup_Prepare( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval); // #47

    // Execute the command ayncronously.
    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval ); // #48

    rval = Tss2_Sys_Startup( sysContext, TPM_SU_CLEAR );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #49

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TPM_RC_INITIALIZE ); // #50

    // Now test case for ExecuteFinish where TPM returns
    // an error.  ExecuteFinish should return same error
    // as TPM.
    rval = Tss2_Sys_Startup_Prepare( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval); // #51

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, &rpBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #52

    // Execute the command ayncronously.
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TPM_RC_INITIALIZE ); // #53

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, &rpBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #54

    // Test one-call for null sysContext pointer.
    rval = Tss2_Sys_Startup( 0, TPM_SU_CLEAR );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #55

    // Test one-call for NULL input parameter that should be a
    // pointer.
    rval = Tss2_Sys_Create( testSysContext, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #56

    // Test GetCommandCode for bad reference
    rval = Tss2_Sys_GetCommandCode( 0, &commandCode );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #57

    rval = Tss2_Sys_GetCommandCode( sysContext, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #58

    //
    // Test GetRpBuffer for case of no response params or handles.
    //
    rval = Tss2_Sys_Shutdown( sysContext, 0, TPM_SU_STATE, 0 );
    CheckPassed( rval ); // #59

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, &rpBuffer );
    CheckPassed( rval ); // #60

    if( rpBufferUsedSize != 0 )
    {
        DebugPrintf( NO_PREFIX, "\nERROR!!  Tss2_Sys_GetRpBuffer returned non-zero size for command that returns no handles or parameters\n" );
        Cleanup();
    }

    //
    // Test GetRpBuffer for case of response params.
    //
    rval = Tss2_Sys_GetCapability( sysContext, 0,
            TPM_CAP_TPM_PROPERTIES, TPM_PT_ACTIVE_SESSIONS_MAX,
            1, &moreData, &capabilityData, 0 );
    CheckPassed(rval); // #61

    rval = Tss2_Sys_GetRpBuffer( sysContext, &rpBufferUsedSize, &rpBuffer );
    CheckPassed( rval ); // #62

    if( rpBufferUsedSize != 17 )
    {
        DebugPrintf( NO_PREFIX, "\nERROR!!  Tss2_Sys_GetRpBuffer returned wrong size for command that returns handles and/or parameters\n" );
        Cleanup();
    }

    // Now compare RP buffer to what it should be
    for( i = 0; i < rpBufferUsedSize; i++ )
    {
        if( rpBuffer[i] != goodRpBuffer[i] )
        {
            rpBufferError = 1;
            break;
        }
    }

    if( rpBufferError )
    {
        DebugPrintf( NO_PREFIX, "\nERROR!!  Tss2_Sys_GetRpBuffer returned wrong rpBuffer contents:\nrpBuffer was: \n\t" );
        DebugPrintBuffer( NO_PREFIX, (UINT8 *)&rpBuffer, rpBufferUsedSize );
        DebugPrintf( NO_PREFIX, "\nrpBuffer s/b:\n\t" );
        DebugPrintBuffer( NO_PREFIX, (UINT8 *)&(goodRpBuffer[0]), rpBufferUsedSize );
        Cleanup();
    }

    TeardownSysContext( &testSysContext );

    rval = Tss2_Sys_GetTestResult_Prepare( sysContext );
    CheckPassed(rval); // #63

    // Execute the command syncronously.
    rval = Tss2_Sys_Execute( sysContext );
    CheckPassed(rval); // #64

    // Get the command results
    // NOTE: this test modifies internal fields of the sysContext structure.
    // DON'T DO THIS IN REAL APPS!!
    savedRspSize = CHANGE_ENDIAN_DWORD( ( (TPM20_Header_Out *)( SYS_CONTEXT->tpmOutBuffPtr )  )->responseSize );
    ( (TPM20_Header_Out *)( SYS_CONTEXT->tpmOutBuffPtr )  )->responseSize = 4097;
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    ( (TPM20_Header_Out *)( SYS_CONTEXT->tpmOutBuffPtr )  )->responseSize = savedRspSize;
    CheckFailed( rval, TSS2_SYS_RC_MALFORMED_RESPONSE ); // #65

    // NOTE: this test case is kind of bogus--no application would ever do this
    // since apps can't change the responseSize after TPM has returned the response.
    // ONce the MALFOMED_RESPONSE occurs, there's no way to recover the response data.
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_GetTestResult_Complete( sysContext, &outData, &testResult );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #66
}


void TestTpmGetCapability()
{
    UINT32 rval;

    char manuID[5] = "    ";
    char *manuIDPtr = &manuID[0];
    TPMI_YES_NO moreData;
    TPMS_CAPABILITY_DATA capabilityData;

    DebugPrintf( NO_PREFIX, "\nGET_CAPABILITY TESTS:\n" );

    rval = Tss2_Sys_GetCapability( sysContext, 0, TPM_CAP_TPM_PROPERTIES, TPM_PT_MANUFACTURER, 1, &moreData, &capabilityData, 0 );
    CheckPassed( rval );

    *( (UINT32 *)manuIDPtr ) = CHANGE_ENDIAN_DWORD( capabilityData.data.tpmProperties.tpmProperty[0].value );
    DebugPrintf( NO_PREFIX, "\t\tcount: %d, property: %x, manuId: %s\n",
            capabilityData.data.tpmProperties.count,
            capabilityData.data.tpmProperties.tpmProperty[0].property,
            manuID );

    rval = Tss2_Sys_GetCapability( sysContext, 0, TPM_CAP_TPM_PROPERTIES, TPM_PT_MAX_COMMAND_SIZE, 1, &moreData, &capabilityData, 0 );
    CheckPassed( rval );
    DebugPrintf( NO_PREFIX, "\t\tcount: %d, property: %x, max cmd size: %d\n",
            capabilityData.data.tpmProperties.count,
            capabilityData.data.tpmProperties.tpmProperty[0].property,
            capabilityData.data.tpmProperties.tpmProperty[0].value );


    rval = Tss2_Sys_GetCapability( sysContext, 0, TPM_CAP_TPM_PROPERTIES, TPM_PT_MAX_COMMAND_SIZE, 40, &moreData, &capabilityData, 0 );
    CheckPassed( rval );
    DebugPrintf( NO_PREFIX, "\t\tcount: %d, property: %x, max cmd size: %d\n",
            capabilityData.data.tpmProperties.count,
            capabilityData.data.tpmProperties.tpmProperty[0].property,
            capabilityData.data.tpmProperties.tpmProperty[0].value );


    rval = Tss2_Sys_GetCapability( sysContext, 0, TPM_CAP_TPM_PROPERTIES, TPM_PT_MAX_RESPONSE_SIZE, 1, &moreData, &capabilityData, 0 );
    CheckPassed( rval );
    DebugPrintf( NO_PREFIX, "\t count: %d, property: %x, max response size: %d\n",
            capabilityData.data.tpmProperties.count,
            capabilityData.data.tpmProperties.tpmProperty[0].property,
            capabilityData.data.tpmProperties.tpmProperty[0].value );

    rval = Tss2_Sys_GetCapability( sysContext, 0, 0xff, TPM_PT_MANUFACTURER, 1, &moreData, &capabilityData, 0 );

    if( tpmSpecVersion == 115 || tpmSpecVersion == 119 )
    {
        CheckFailed( rval, TPM_RC_VALUE );
    }
    else
    {
        CheckFailed( rval, TPM_RC_VALUE+TPM_RC_1+TPM_RC_P );
    }
}

void TestTpmClear()
{
    UINT32 rval;
    TPM2B_AUTH      hmac;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TPM2B_NONCE     nonce;
    TSS2_SYS_CMD_AUTHS sessionsDataIn;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsDataIn.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;
    sessionsDataOut.rspAuths[0] = &sessionDataOut;

    DebugPrintf( NO_PREFIX, "\nCLEAR and CLEAR CONTROL TESTS:\n" );

    // Init sessionHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    nonce.t.size = 0;
    sessionData.nonce = nonce;

    // init hmac
    hmac.t.size = 0;
    sessionData.hmac = hmac;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsDataIn.cmdAuthsCount = 1;
    sessionsDataIn.cmdAuths[0] = &sessionData;

    rval = Tss2_Sys_Clear ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_ClearControl ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, YES, &sessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_Clear ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, 0 );
    CheckFailed( rval, TPM_RC_DISABLED );

    rval = Tss2_Sys_ClearControl ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, NO, &sessionsDataOut );
    CheckPassed( rval );

    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0xff;
    sessionsDataIn.cmdAuths[0] = &sessionData;
    rval = Tss2_Sys_Clear ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_9 + TPM_RC_RESERVED_BITS );

    rval = Tss2_Sys_ClearControl ( sysContext, TPM_RH_PLATFORM, &sessionsDataIn, NO, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_9 + TPM_RC_RESERVED_BITS );

    hmac.t.size = 0;


}

#define SESSIONS_ABOVE_MAX_ACTIVE 0
#define DEBUG_MAX_ACTIVE_SESSIONS   8
#define DEBUG_GAP_MAX   2*DEBUG_MAX_ACTIVE_SESSIONS

SESSION *sessions[SESSIONS_COUNT];

void TestStartAuthSession()
{
    UINT32 rval;
    TPM2B_ENCRYPTED_SECRET encryptedSalt;
    TPMT_SYM_DEF symmetric;
    SESSION *authSession;
    TPM2B_NONCE nonceCaller;
    UINT16 i;
    TPM_HANDLE badSessionHandle = 0x03010000;

    TPMS_AUTH_COMMAND sessionData;
    TPM2B_NONCE     nonce;


    TPM2B_AUTH      hmac;


    // Init sessionHandle
    sessionData.sessionHandle = badSessionHandle;

    // Init nonce.
    nonce.t.size = 0;
    sessionData.nonce = nonce;

    // init hmac
    hmac.t.size = 0;
    sessionData.hmac = hmac;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    encryptedSalt.t.size = 0;

    DebugPrintf( NO_PREFIX, "\nSTART_AUTH_SESSION TESTS:\n" );

    symmetric.algorithm = TPM_ALG_NULL;
    symmetric.keyBits.sym = 0;
    symmetric.mode.sym = 0;

    nonceCaller.t.size = 0;

    encryptedSalt.t.size = 0;

     // Init session
    rval = StartAuthSessionWithParams( &authSession, TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );

    rval = Tss2_Sys_FlushContext( sysContext, authSession->sessionHandle );
    CheckPassed( rval );
    EndAuthSession( authSession );

    // Init session
    rval = StartAuthSessionWithParams( &authSession, TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, 0xff, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckFailed( rval, TPM_RC_VALUE + TPM_RC_P + TPM_RC_3 );

    // Try starting a bunch to see if resource manager handles this correctly.
    for( i = 0; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ )
    {
//        DebugPrintf( NO_PREFIX, "i = 0x%4.4x\n", i );

        // Init session struct
        rval = StartAuthSessionWithParams( &sessions[i], TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
        CheckPassed( rval );
        DebugPrintf( NO_PREFIX, "Number of sessions created: %d\n\n", i+1 );

    }
    
#ifdef SKIP_BAD_HANDLE_TEST
    printf("** Skipping bad session handle test\n");
#else
    // Now try two ways of using a bad session handle.  Both should fail.
    // first way is to use as command parameter.
    TPMA_LOCALITY locality;
    TSS2_SYS_CMD_AUTHS sessionsDataIn;
    TPMS_AUTH_COMMAND *sessionDataArray[1];

    sessionDataArray[0] = &sessionData;
    sessionsDataIn.cmdAuths = &sessionDataArray[0];
    sessionsDataIn.cmdAuthsCount = 1;

    *(UINT8 *)( (void *)&locality ) = 0;
    locality.TPM_LOC_THREE = 1;
    rval = Tss2_Sys_PolicyLocality( sysContext, badSessionHandle, 0, locality, 0 );
    CheckFailed( rval, TSS2_RESMGRTPM_ERROR_LEVEL + TPM_RC_HANDLE + ( 1 << 8 ) );

    // Second way is to use as handle in session area.
    rval = Tss2_Sys_PolicyLocality( sysContext, sessions[0]->sessionHandle, &sessionsDataIn, locality, 0 );
    CheckFailed( rval, TSS2_RESMGRTPM_ERROR_LEVEL + TPM_RC_VALUE + TPM_RC_S + ( 1 << 8 ) );
#endif // SKIP_1
    
    // clean up the sessions that I don't want here.
    for( i = 0; i < ( sizeof(sessions) / sizeof (SESSION *)); i++ )
    {
//        DebugPrintf( NO_PREFIX, "i(2) = 0x%4.4x\n", i );
        rval = Tss2_Sys_FlushContext( sysContext, sessions[i]->sessionHandle );

        rval = EndAuthSession( sessions[i] );
    }

    // Now do some gap tests.
    rval = StartAuthSessionWithParams( &sessions[0], TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );

    for( i = 1; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ )
    {
//        DebugPrintf( NO_PREFIX, "i(3) = 0x%4.4x\n", i );

        rval = StartAuthSessionWithParams( &sessions[i], TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
        CheckPassed( rval );

        rval = Tss2_Sys_FlushContext( sysContext, sessions[i]->sessionHandle );
        CheckPassed( rval );

        rval = EndAuthSession( sessions[i] );
        CheckPassed( rval );
    }

    for( i = 0; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ )
    {
//        DebugPrintf( NO_PREFIX, "i(4) = 0x%4.4x\n", i );
        rval = StartAuthSessionWithParams( &sessions[i], TPM_RH_NULL, 0, TPM_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
        CheckPassed( rval );

        rval = Tss2_Sys_FlushContext( sysContext, sessions[i]->sessionHandle );
        CheckPassed( rval );

        rval = EndAuthSession( sessions[i] );
        CheckPassed( rval );

    }
}

void TestChangeEps()
{
    UINT32 rval;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nCHANGE_EPS TESTS:\n" );

	sessionsData.cmdAuthsCount = 1;

    // Init authHandle
    sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionsData.cmdAuths[0]->nonce.t.size = 0;

    // init hmac
    sessionsData.cmdAuths[0]->hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionsData.cmdAuths[0]->sessionAttributes ) ) = 0;

    rval = Tss2_Sys_ChangeEPS( sysContext, TPM_RH_PLATFORM, &sessionsData, &sessionsDataOut );
    CheckPassed( rval );

    sessionsData.cmdAuths[0]->hmac.t.size = 0x10;

    rval = Tss2_Sys_ChangeEPS( sysContext, TPM_RH_PLATFORM, &sessionsData, 0 );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_S + TPM_RC_BAD_AUTH );
}

void TestChangePps()
{
    UINT32 rval;
    TSS2_SYS_CMD_AUTHS sessionsData;

    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nCHANGE_PPS TESTS:\n" );

    sessionsData.cmdAuthsCount = 1;

    // Init authHandle
    sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionsData.cmdAuths[0]->nonce.t.size = 0;

    // init hmac
    sessionsData.cmdAuths[0]->hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionsData.cmdAuths[0]->sessionAttributes ) ) = 0;

    rval = Tss2_Sys_ChangePPS( sysContext, TPM_RH_PLATFORM, &sessionsData, &sessionsDataOut );
    CheckPassed( rval );

    sessionsData.cmdAuths[0]->hmac.t.size = 0x10;

    rval = Tss2_Sys_ChangePPS( sysContext, TPM_RH_PLATFORM, &sessionsData, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_S + TPM_RC_BAD_AUTH );
}

void TestHierarchyChangeAuth()
{
    UINT32 rval;
    TPM2B_AUTH      newAuth;
    TPMS_AUTH_COMMAND sessionData;
    TSS2_SYS_CMD_AUTHS sessionsData;
    int i;

    TPMS_AUTH_COMMAND *sessionDataArray[1];

    sessionDataArray[0] = &sessionData;

    sessionsData.cmdAuths = &sessionDataArray[0];

    DebugPrintf( NO_PREFIX, "\nHIERARCHY_CHANGE_AUTH TESTS:\n" );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    newAuth.t.size = 0;
    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, TPM_RH_PLATFORM, &sessionsData, &newAuth, 0 );
    CheckPassed( rval );

    // Init new auth
    newAuth.t.size = 20;
    for( i = 0; i < newAuth.t.size; i++ )
        newAuth.t.buffer[i] = i;

    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, TPM_RH_PLATFORM, &sessionsData, &newAuth, 0 );
    CheckPassed( rval );

    sessionData.hmac = newAuth;
    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, TPM_RH_PLATFORM, &sessionsData, &newAuth, 0 );
    CheckPassed( rval );

    // Init new auth
    newAuth.t.size = 0;

    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, TPM_RH_PLATFORM, &sessionsData, &newAuth, 0 );
    CheckPassed( rval );

    sessionsData.cmdAuths[0] = &sessionData;
    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, TPM_RH_PLATFORM, &sessionsData, &newAuth, 0 );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_S + TPM_RC_BAD_AUTH );

    rval = Tss2_Sys_HierarchyChangeAuth( sysContext, 0, &sessionsData, &newAuth, 0 );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_VALUE );
}

#define PCR_0   0
#define PCR_1   1
#define PCR_2   2
#define PCR_3   3
#define PCR_4   4
#define PCR_5   5
#define PCR_6   6
#define PCR_7   7
#define PCR_8   8
#define PCR_9   9
#define PCR_10  10
#define PCR_11  11
#define PCR_12  12
#define PCR_13  13
#define PCR_14  14
#define PCR_15  15
#define PCR_16  16
#define PCR_17  17
#define PCR_18  18

#define PCR_SIZE 20

void TestPcrExtend()
{
    UINT32 rval;
    TPMS_AUTH_COMMAND sessionData;
    TSS2_SYS_CMD_AUTHS sessionsData;
    UINT16 i, digestSize;
    TPML_PCR_SELECTION  pcrSelection;
    UINT32 pcrUpdateCounterBeforeExtend;
    UINT32 pcrUpdateCounterAfterExtend;
    UINT8 pcrBeforeExtend[PCR_SIZE];
    TPM2B_EVENT eventData;
    TPML_DIGEST pcrValues;
    TPML_DIGEST_VALUES digests;
    TPML_PCR_SELECTION pcrSelectionOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];

    sessionDataArray[0] = &sessionData;
    sessionsData.cmdAuths = &sessionDataArray[0];

    DebugPrintf( NO_PREFIX, "\nPCR_EXTEND, PCR_EVENT, PCR_ALLOCATE, and PCR_READ TESTS:\n" );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    // Init digests
    digests.count = 1;
    digests.digests[0].hashAlg = TPM_ALG_SHA1;
    digestSize = GetDigestSize( digests.digests[0].hashAlg );

    for( i = 0; i < digestSize; i++ )
    {
        digests.digests[0].digest.sha1[i] = (UINT8)(i % 256);
    }

    pcrSelection.count = 1;
    pcrSelection.pcrSelections[0].hash = TPM_ALG_SHA1;
    pcrSelection.pcrSelections[0].sizeofSelect = 3;

    // Clear out PCR select bit field
    pcrSelection.pcrSelections[0].pcrSelect[0] = 0;
    pcrSelection.pcrSelections[0].pcrSelect[1] = 0;
    pcrSelection.pcrSelections[0].pcrSelect[2] = 0;

    // Now set the PCR you want to read
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[0], PCR_17 );

    rval = Tss2_Sys_PCR_Read( sysContext, 0, &pcrSelection, &pcrUpdateCounterBeforeExtend, &pcrSelectionOut, &pcrValues, 0 );
    CheckPassed( rval );

    if( pcrValues.digests[0].t.size <= PCR_SIZE &&
            pcrValues.digests[0].t.size <= sizeof( pcrValues.digests[0].t.buffer ) )
        memcpy( &( pcrBeforeExtend[0] ), &( pcrValues.digests[0].t.buffer[0] ), pcrValues.digests[0].t.size );

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    rval = Tss2_Sys_PCR_Extend( sysContext, PCR_17, &sessionsData, &digests, 0  );
    CheckPassed( rval );

    rval = Tss2_Sys_PCR_Read( sysContext, 0, &pcrSelection, &pcrUpdateCounterAfterExtend, &pcrSelectionOut, &pcrValues, 0 );
    CheckPassed( rval );

    memcpy( &( pcrAfterExtend[0] ), &( pcrValues.digests[0].t.buffer[0] ), pcrValues.digests[0].t.size );

    if( pcrUpdateCounterBeforeExtend == pcrUpdateCounterAfterExtend )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! pcrUpdateCounter didn't change value\n" );
        Cleanup();
    }

    if( 0 == memcmp( &( pcrBeforeExtend[0] ), &( pcrAfterExtend[0] ), 20 ) )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! PCR didn't change value\n" );
        Cleanup();
    }

    pcrSelection.pcrSelections[0].sizeofSelect = 4;

    rval = Tss2_Sys_PCR_Read( sysContext, 0, &pcrSelection, &pcrUpdateCounterAfterExtend, 0, 0, 0 );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_P + TPM_RC_VALUE );

    eventData.t.size = 4;
    eventData.t.buffer[0] = 0;
    eventData.t.buffer[1] = 0xff;
    eventData.t.buffer[2] = 0x55;
    eventData.t.buffer[3] = 0xaa;

    rval = Tss2_Sys_PCR_Event( sysContext, PCR_18, &sessionsData, &eventData, &digests, 0  );
    CheckPassed( rval );
}

void TestShutdown()
{
    UINT32 rval;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];
    TPMS_AUTH_RESPONSE sessionDataOut;

    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nSHUTDOWN TESTS:\n" );

    rval = Tss2_Sys_Shutdown( sysContext, 0, TPM_SU_STATE, &sessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_Shutdown( sysContext, 0, TPM_SU_CLEAR, &sessionsDataOut );
    CheckPassed( rval );

    if( !( tpmSpecVersion == 115 || tpmSpecVersion == 119 ) )
    {
        rval = Tss2_Sys_Shutdown( sysContext, 0, 0xff, 0 );
        CheckFailed( rval, TPM_RC_VALUE+TPM_RC_1+TPM_RC_P );
    }
}

void TestNV()
{
    UINT32 rval;
    TPM2B_NV_PUBLIC publicInfo;
    TPM2B_AUTH  nvAuth;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    int i;
    TPM2B_MAX_NV_BUFFER nvWriteData;
    TPM2B_MAX_NV_BUFFER nvData;

    TPM2B_NV_PUBLIC nvPublic;
    TPM2B_NAME nvName;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nNV INDEX TESTS:\n" );

    nvAuth.t.size = 20;
    for( i = 0; i < nvAuth.t.size; i++ )
        nvAuth.t.buffer[i] = (UINT8)i;

    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
        sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
        sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = TPM20_INDEX_TEST1;
    publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA1;

    // First zero out attributes.
    *(UINT32 *)&( publicInfo.t.nvPublic.attributes ) = 0;

    // Now set the attributes.
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_WRITE_STCLEAR = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_ORDERLY = 1;
    publicInfo.t.nvPublic.authPolicy.t.size = 0;
    publicInfo.t.nvPublic.dataSize = 32;

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 32, 0, &nvData, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_2 + TPM_RC_HANDLE );

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut );
    CheckPassed( rval );

    nvPublic.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( nvName );
    rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST1, 0, &nvPublic, &nvName, 0 );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 32, 0, &nvData, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_NV_UNINITIALIZED );

    // Should fail since index is already defined.
    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_NV_DEFINED );

    nvWriteData.t.size = 4;
    for( i = 0; i < nvWriteData.t.size; i++ )
        nvWriteData.t.buffer[i] = 0xff - i;

#if 1
    //
    // Following, at one point, was commented out so that NVDefine will work on successive
    // invocations of client app.
    //
    // Noticed on 12/13/12, this doesn't seem to be necessary anymore.  Maybe something else
    // I did fixed it.
    //
    // Seems to be a bug in TPM 2.0 simulator that if:
    //   First pass of tpmclient.exe after restarting TPM 2.0 simulator will work fine.
    //   If NVWrite is done, subsequent invocations of tpmclient.exe will ALWAYS fail on
    //      first call to Tpm2NVDefineSpace with 0x2cb error. Removing NVWrite removes this.
    //      And restarting TPM 2.0 simulator will make it work the first time and fail
    //      subsequent times.
    //      Removing NVWrite works around this problem.
    //
    rval = Tss2_Sys_NV_Write( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, &nvWriteData, 0, &sessionsDataOut );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 32, 0, &nvData, &sessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_WriteLock( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, &sessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_Write( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, &nvWriteData, 0, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_NV_LOCKED );
#endif

    // Now undefine the index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, 0 );
    CheckPassed( rval );

    // Now undefine the index so that next run will work correctly.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 0 );
    CheckPassed( rval );

    publicInfo.t.nvPublic.attributes.TPMA_NV_PPREAD = 0;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPWRITE = 0;
    publicInfo.t.nvPublic.attributes.TPMA_NV_OWNERREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_OWNERWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 0;
    publicInfo.t.nvPublic.attributes.TPMA_NV_ORDERLY = 1;
    publicInfo.t.nvPublic.nvIndex = TPM20_INDEX_TEST2;
    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_OWNER, &sessionsData, &nvAuth, &publicInfo, 0 );
    CheckPassed( rval );

    nvPublic.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( nvName );
    rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST2, 0, &nvPublic, &nvName, 0 );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST2, &sessionsData, 32, 0, &nvData, 0 );
    CheckFailed( rval, TPM_RC_NV_AUTHORIZATION );

    // Now undefine the index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_OWNER, TPM20_INDEX_TEST2, &sessionsData, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_OWNER, &sessionsData, &nvAuth, &publicInfo, 0 );
    CheckPassed( rval );

    // Now undefine the index so that next run will work correctly.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_OWNER, TPM20_INDEX_TEST2, &sessionsData, 0 );
    CheckPassed( rval );
}

void TestHierarchyControl()
{
    UINT32 rval;
    TPM2B_NV_PUBLIC publicInfo;
    TPM2B_AUTH  nvAuth;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    int i;
    TPM2B_NAME nvName;
    TPM2B_NV_PUBLIC nvPublic;
    TPM2B_MAX_NV_BUFFER nvData;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nHIERARCHY CONTROL TESTS:\n" );

    nvAuth.t.size = 20;
    for( i = 0; i < nvAuth.t.size; i++ )
        nvAuth.t.buffer[i] = i;

    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
        sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
        sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = TPM20_INDEX_TEST1;
    publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA1;

    // First zero out attributes.
    *(UINT32 *)&( publicInfo.t.nvPublic.attributes ) = 0;

    // Now set the attributes.
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PPWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_WRITE_STCLEAR = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_ORDERLY = 1;
    publicInfo.t.nvPublic.authPolicy.t.size = 0;
    publicInfo.t.nvPublic.dataSize = 32;

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, 0 );
    CheckPassed( rval );

    // Test SAPI for case where nvPublic.t.size != 0
    nvPublic.t.size = 0xff;
    INIT_SIMPLE_TPM2B_SIZE( nvName );
    rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST1, 0, &nvPublic, &nvName, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE );

    nvPublic.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( nvName );
    rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST1, 0, &nvPublic, &nvName, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 32, 0, &nvData, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_NV_UNINITIALIZED );

    rval = Tss2_Sys_HierarchyControl( sysContext, TPM_RH_PLATFORM, &sessionsData, TPM_RH_PLATFORM, NO, &sessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_Read( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 32, 0, &nvData, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_HIERARCHY );

    rval = Tss2_Sys_HierarchyControl( sysContext, TPM_RH_PLATFORM, &sessionsData, TPM_RH_PLATFORM, YES, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_1 + TPM_RC_HIERARCHY );

    // Need to do TPM reset and Startup to re-enable platform hierarchy.
    rval = TpmReset();
    CheckPassed(rval);

    rval = Tss2_Sys_Startup ( sysContext, TPM_SU_CLEAR );
    CheckPassed( rval );

    rval = Tss2_Sys_HierarchyControl( sysContext, TPM_RH_PLATFORM, &sessionsData, TPM_RH_PLATFORM, YES, &sessionsDataOut );
    CheckPassed( rval );

    // Now undefine the index so that next run will work correctly.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &sessionsData, 0 );
    CheckPassed( rval );
}

TPM2B_PUBLIC    inPublic = { { sizeof( TPM2B_PUBLIC ) - 2, } };

void TestCreate(){
    UINT32 rval;
    TPM2B_SENSITIVE_CREATE  inSensitive = { { sizeof( TPM2B_SENSITIVE_CREATE ) - 2, } };
    TPM2B_DATA              outsideInfo = { { sizeof( TPM2B_DATA ) - 2, } };
    TPML_PCR_SELECTION      creationPCR;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;

    TSS2_SYS_RSP_AUTHS sessionsDataOut;
	TPM2B_NAME name = { { sizeof( TPM2B_NAME ) - 2, } };
	TPM2B_NAME name1 = { { sizeof( TPM2B_NAME ) - 2, } };
    TPM2B_PRIVATE outPrivate = { { sizeof( TPM2B_PRIVATE ) - 2, } };
    TPM2B_PUBLIC outPublic = { { sizeof( TPM2B_PUBLIC ) - 2, } };
    TPM2B_CREATION_DATA creationData =  { { sizeof( TPM2B_CREATION_DATA ) - 2, } };
	TPM2B_DIGEST creationHash = { { sizeof( TPM2B_DIGEST ) - 2, } };
	TPMT_TK_CREATION creationTicket = { 0, 0, { { sizeof( TPM2B_DIGEST ) - 2, } } };

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nCREATE, CREATE PRIMARY, and LOAD TESTS:\n" );

    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.data.t.size = 0;
    inSensitive.t.size = loadedSha1KeyAuth.b.size + 2;

    inPublic.t.publicArea.type = TPM_ALG_RSA;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;

    // First clear attributes bit field.
    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.restricted = 1;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;
    inPublic.t.publicArea.objectAttributes.decrypt = 1;
    inPublic.t.publicArea.objectAttributes.fixedTPM = 1;
    inPublic.t.publicArea.objectAttributes.fixedParent = 1;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 1;

    inPublic.t.publicArea.authPolicy.t.size = 0;

    inPublic.t.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_ECB;
    inPublic.t.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 1024;
    inPublic.t.publicArea.parameters.rsaDetail.exponent = 0;

    inPublic.t.publicArea.unique.rsa.t.size = 0;

    outsideInfo.t.size = 0;
    creationPCR.count = 0;

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 2048;

    // Do SAPI test for non-zero sized outPublic
    outPublic.t.size = 0xff;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_PLATFORM, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &handle2048rsa, &outPublic, &creationData, &creationHash,
            &creationTicket, &name, &sessionsDataOut );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE );

    rval = Tss2_Sys_FlushContext( sysContext, handle2048rsa );
    CheckPassed( rval );

    outPublic.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationData );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_PLATFORM, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &handle2048rsa, &outPublic, &creationData, &creationHash,
            &creationTicket, &name, &sessionsDataOut );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE );

    rval = Tss2_Sys_FlushContext( sysContext, handle2048rsa );
    CheckPassed( rval );

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_PLATFORM, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &handle2048rsa, &outPublic, &creationData, &creationHash,
            &creationTicket, &name, &sessionsDataOut );
    CheckPassed( rval );

    DebugPrintf( NO_PREFIX, "\nNew key successfully created in platform hierarchy (RSA 2048).  Handle: 0x%8.8x\n",
            handle2048rsa );

    sessionData.hmac.t.size = 2;
    sessionData.hmac.t.buffer[0] = 0x00;
    sessionData.hmac.t.buffer[1] = 0xff;

    inPublic.t.publicArea.type = TPM_ALG_KEYEDHASH;
    inPublic.t.publicArea.objectAttributes.decrypt = 0;
    inPublic.t.publicArea.objectAttributes.sign = 1;

    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_HMAC;
    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = TPM_ALG_SHA1;

    inPublic.t.publicArea.unique.keyedHash.t.size = 0;

    outsideInfo.t.size = 0;
    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( outPrivate );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    rval = TSS2_RETRY_EXP( Tss2_Sys_Create( sysContext, handle2048rsa, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR,
            &outPrivate, &outPublic, &creationData,
            &creationHash, &creationTicket, &sessionsDataOut ));
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_Load ( sysContext, handle2048rsa, &sessionsData, &outPrivate, &outPublic,
            &loadedSha1KeyHandle, &name, &sessionsDataOut);
    CheckPassed( rval );

    rval = (*HandleToNameFunctionPtr)( loadedSha1KeyHandle, &name1 );
    CheckPassed( rval );
    DebugPrintf( NO_PREFIX, "Name of loaded key: " );
    PrintSizedBuffer( (TPM2B *)&name1 );

    rval = CompareTPM2B( &name.b, &name1.b );
    CheckPassed( rval );

    DebugPrintf( NO_PREFIX, "\nLoaded key handle:  %8.8x\n", loadedSha1KeyHandle );
}

void TestEvict()
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPM2B_SENSITIVE_CREATE  inSensitive = { { sizeof( TPM2B_SENSITIVE_CREATE ) - 2, } };
    TPM2B_DATA              outsideInfo = { { sizeof( TPM2B_DATA ) - 2, } };
    TPML_PCR_SELECTION      creationPCR;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPM2B_PRIVATE outPrivate = { { sizeof( TPM2B_PRIVATE ) - 2, } };
    TPM2B_PUBLIC outPublic = { { sizeof( TPM2B_PUBLIC ) - 2, } };
    TPM2B_CREATION_DATA creationData =  { { sizeof( TPM2B_CREATION_DATA ) - 2, } };
	TPM2B_DIGEST creationHash = { { sizeof( TPM2B_DIGEST ) - 2, } };
	TPMT_TK_CREATION creationTicket = { 0, 0, { { sizeof( TPM2B_DIGEST ) - 2, } } };

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];
    sessionsData.cmdAuthsCount = 1;

    sessionsDataOut.rspAuthsCount = 1;

    outsideInfo.t.size = 0;
    creationPCR.count = 0;

    DebugPrintf( NO_PREFIX, "\nEVICT CONTROL TESTS:\n" );

    // Make transient key persistent.
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    rval = Tss2_Sys_EvictControl( sysContext, TPM_RH_PLATFORM, handle2048rsa, &sessionsData, 0x81800000, &sessionsDataOut );
    CheckPassed( rval );

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    // Create new key under persistent one.
    sessionData.hmac.t.size = 2;
    sessionData.hmac.t.buffer[0] = 0x00;
    sessionData.hmac.t.buffer[1] = 0xff;

    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;
    inPublic.t.publicArea.type = TPM_ALG_KEYEDHASH;
    inPublic.t.publicArea.objectAttributes.decrypt = 0;
    inPublic.t.publicArea.objectAttributes.sign = 1;

    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_HMAC;
    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = TPM_ALG_SHA1;

    inPublic.t.publicArea.unique.keyedHash.t.size = 0;

    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.data.t.size = 0;
    inSensitive.t.size = loadedSha1KeyAuth.b.size + 2;

    outsideInfo.t.size = 0;
    outPublic.t.size = 0;
    creationData.t.size = 0;

    // Try creating a key under the persistent key using a different context.
    rval = Tss2_Sys_Create( sysContext, 0x81800000, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR,
            &outPrivate, &outPublic, &creationData,
            &creationHash, &creationTicket, &sessionsDataOut );
    CheckPassed( rval );

    outsideInfo.t.size = 0;
    outPublic.t.size = 0;
    creationData.t.size = 0;

    // Try creating a key under the transient key.  This should work, too.
    INIT_SIMPLE_TPM2B_SIZE( outPrivate );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    rval = Tss2_Sys_Create( sysContext, handle2048rsa, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR,
            &outPrivate, &outPublic, &creationData,
            &creationHash, &creationTicket, &sessionsDataOut );
    CheckPassed( rval );

    // Reset persistent key to be transitent.
    sessionData.hmac.t.size = 0;
    rval = Tss2_Sys_EvictControl( sysContext, TPM_RH_PLATFORM, 0x81800000, &sessionsData, 0x81800000, &sessionsDataOut );
    CheckPassed( rval );
}

TPM_RC DefineNvIndex( TPMI_RH_PROVISION authHandle, TPMI_SH_AUTH_SESSION sessionAuthHandle, TPM2B_AUTH *auth, TPM2B_DIGEST *authPolicy,
    TPMI_RH_NV_INDEX nvIndex, TPMI_ALG_HASH nameAlg, TPMA_NV attributes, UINT16 size  )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPM2B_NV_PUBLIC publicInfo;

    // Command and response session data structures.
    TPMS_AUTH_COMMAND sessionData = { sessionAuthHandle, };
    TPMS_AUTH_RESPONSE sessionDataOut;
    TPMS_AUTH_COMMAND *sessionDataArray[1] = { &sessionData };
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1] = { &sessionDataOut };
    TSS2_SYS_CMD_AUTHS sessionsData = { 1, &sessionDataArray[0] };
    TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, &sessionDataOutArray[0] };
    // Init nonce.
    sessionData.nonce.t.size = 0;
    // init hmac
    sessionData.hmac.t.size = 0;
    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    attributes.TPMA_NV_ORDERLY = 1;

    // Init public info structure.
    publicInfo.t.nvPublic.attributes = attributes;
    CopySizedByteBuffer( &publicInfo.t.nvPublic.authPolicy.b, &authPolicy->b );
    publicInfo.t.nvPublic.dataSize = size;
    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
            sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
            sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = nvIndex;
    publicInfo.t.nvPublic.nameAlg = nameAlg;

    // Create the index
    rval = Tss2_Sys_NV_DefineSpace( sysContext, authHandle, &sessionsData, auth, &publicInfo, &sessionsDataOut );

    return rval;
}

typedef struct {
    char name[50];
    TPM_RC (*buildPolicyFn )( TSS2_SYS_CONTEXT *sysContext, SESSION *trialPolicySession, TPM2B_DIGEST *policyDigest );
    TPM_RC (*createObjectFn )( TSS2_SYS_CONTEXT *sysContext, SESSION **policySession, TPM2B_DIGEST *policyDigest );
    TPM_RC (*testPolicyFn )( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession );
} POLICY_TEST_SETUP;

TPM_RC BuildPolicy( TSS2_SYS_CONTEXT *sysContext, SESSION **policySession,
    TPM_RC (*buildPolicyFn )( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession, TPM2B_DIGEST *policyDigest ),
    TPM2B_DIGEST *policyDigest, bool trialSession )
{
    // NOTE:  this policySession will be either a trial or normal policy session
    // depending on the value of the passed in trialSession parameter.
    TPM2B_ENCRYPTED_SECRET  encryptedSalt = { {0}, };
    TPMT_SYM_DEF symmetric;
    TPM_RC rval;
    TPM2B_NONCE nonceCaller;

    nonceCaller.t.size = 0;

    // Start policy session.
    symmetric.algorithm = TPM_ALG_NULL;
    rval = StartAuthSessionWithParams( policySession, TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, trialSession ? TPM_SE_TRIAL : TPM_SE_POLICY , &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    if( rval != TPM_RC_SUCCESS )
        return rval;

    // Send policy command.
    rval = ( *buildPolicyFn )( sysContext, *policySession, policyDigest );
    CheckPassed( rval );

    // Get policy hash.
    INIT_SIMPLE_TPM2B_SIZE( *policyDigest );
    rval = Tss2_Sys_PolicyGetDigest( sysContext, (*policySession)->sessionHandle,
            0, policyDigest, 0 );
    CheckPassed( rval );

    if( trialSession )
    {
        // Need to flush the session here.
        rval = Tss2_Sys_FlushContext( sysContext, (*policySession)->sessionHandle );
        CheckPassed( rval );

        // And remove the session from sessions table.
        rval = EndAuthSession( *policySession );
        CheckPassed( rval );
    }

    return rval;
}

TPM_RC CreateNVIndex( TSS2_SYS_CONTEXT *sysContext, SESSION **policySession, TPM2B_DIGEST *policyDigest )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPMA_LOCALITY locality;
    TPM2B_ENCRYPTED_SECRET encryptedSalt = { {0}, };
    TPMT_SYM_DEF symmetric;
    TPMA_NV nvAttributes;
    TPM2B_AUTH  nvAuth;
    TPM2B_NONCE nonceCaller;

    nonceCaller.t.size = 0;

    // Since locality is a fairly simple command and we can guarantee
    // its correctness, we don't need a trial session for this.

    // Start real policy session
    symmetric.algorithm = TPM_ALG_NULL;
    rval = StartAuthSessionWithParams( policySession, TPM_RH_NULL,
            0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );

    // Send PolicyLocality command
    *(UINT8 *)( (void *)&locality ) = 0;
    locality.TPM_LOC_THREE = 1;
    rval = Tss2_Sys_PolicyLocality( sysContext, (*policySession)->sessionHandle,
            0, locality, 0 );
    CheckPassed( rval );

    // Read policyHash
    INIT_SIMPLE_TPM2B_SIZE( *policyDigest );
    rval = Tss2_Sys_PolicyGetDigest( sysContext,
            (*policySession)->sessionHandle, 0, policyDigest, 0 );
    CheckPassed( rval );

    nvAuth.t.size = 0;

    // Now set the attributes.
    *(UINT32 *)( (void *)&nvAttributes ) = 0;
    nvAttributes.TPMA_NV_POLICYREAD = 1;
    nvAttributes.TPMA_NV_POLICYWRITE = 1;
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW, &nvAuth, policyDigest,
            TPM20_INDEX_PASSWORD_TEST, TPM_ALG_SHA256, nvAttributes, 32  );
    CheckPassed( rval );

    AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );
    CheckPassed( rval );

    return rval;
}


TPM_RC TestLocality( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession )
{
    TSS2_RC rval = TPM_RC_SUCCESS;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TPM2B_MAX_NV_BUFFER nvWriteData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, };
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    // Init write data.
    nvWriteData.t.size = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0]->sessionHandle = policySession->sessionHandle;
    sessionsData.cmdAuths[0]->nonce.t.size = 0;
    sessionsData.cmdAuths[0]->hmac.t.size = 0;

    *(UINT8 *)( (void *)&( sessionsData.cmdAuths[0]->sessionAttributes ) ) = 0;
     sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 1;

    rval = SetLocality( sysContext, 2 );
    CheckPassed( rval );

    // Do NV write using open session's policy.
    rval = Tss2_Sys_NV_Write( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &sessionsData, &nvWriteData, 0, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_LOCALITY );

    rval = SetLocality( sysContext, 3 );
    CheckPassed( rval );

    // Do NV write using open session's policy.
    rval = Tss2_Sys_NV_Write( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &sessionsData, &nvWriteData, 0, &sessionsDataOut );
    CheckPassed( rval );

    // Do another NV write using open session's policy.
    rval = Tss2_Sys_NV_Write( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &sessionsData, &nvWriteData, 0, &sessionsDataOut );
    CheckFailed( rval, TPM_RC_POLICY_FAIL + TPM_RC_S + TPM_RC_1 );

    // Delete NV index
    sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;
    sessionsData.cmdAuths[0]->nonce.t.size = 0;
    sessionsData.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
    sessionData.hmac.t.size = 0;

    // Now undefine the index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM,
            TPM20_INDEX_PASSWORD_TEST, &sessionsData, 0 );
    CheckPassed( rval );

    rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );
    CheckPassed( rval );

    return rval;
}

UINT8 passwordPCRTestPassword[] = "password PCR";
UINT8 dataBlob[] = "some data";
TPM_HANDLE blobHandle;
TPM2B_AUTH blobAuth;

TPM_RC BuildPasswordPolicy( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession, TPM2B_DIGEST *policyDigest )
{
    TPM_RC rval = TPM_RC_SUCCESS;

    rval = Tss2_Sys_PolicyPassword( sysContext, policySession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    return rval;
}

TPM_RC BuildAuthValuePolicy( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession, TPM2B_DIGEST *policyDigest )
{
    TPM_RC rval = TPM_RC_SUCCESS;

    rval = Tss2_Sys_PolicyAuthValue( sysContext, policySession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    return rval;
}


TPM_RC BuildPasswordPcrPolicy( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession, TPM2B_DIGEST *policyDigest )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPM2B_DIGEST pcrDigest;
    TPML_PCR_SELECTION pcrs;
    TPML_DIGEST pcrValues;
    UINT32 pcrUpdateCounter;
    TPML_PCR_SELECTION pcrSelectionOut;

    pcrDigest.t.size = 0;
    rval = Tss2_Sys_PolicyPassword( sysContext, policySession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    pcrs.count = 1;
    pcrs.pcrSelections[0].hash = TPM_ALG_SHA1;
    pcrs.pcrSelections[0].sizeofSelect = 3;
    pcrs.pcrSelections[0].pcrSelect[0] = 0;
    pcrs.pcrSelections[0].pcrSelect[1] = 0;
    pcrs.pcrSelections[0].pcrSelect[2] = 0;
    SET_PCR_SELECT_BIT( pcrs.pcrSelections[0], PCR_0 );
    SET_PCR_SELECT_BIT( pcrs.pcrSelections[0], PCR_3 );

    //
    // Compute pcrDigest
    //
    // Read PCRs
    rval = Tss2_Sys_PCR_Read( sysContext, 0, &pcrs, &pcrUpdateCounter, &pcrSelectionOut, &pcrValues, 0 );
    CheckPassed( rval );

    // Hash them together
    INIT_SIMPLE_TPM2B_SIZE( pcrDigest );
    rval = TpmHashSequence( policySession->authHash, pcrValues.count, &pcrValues.digests[0], &pcrDigest );
    CheckPassed( rval );

    rval = Tss2_Sys_PolicyPCR( sysContext, policySession->sessionHandle, 0, &pcrDigest, &pcrs, 0 );
    CheckPassed( rval );

    return rval;
}


TPM_RC CreateDataBlob( TSS2_SYS_CONTEXT *sysContext, SESSION **policySession, TPM2B_DIGEST *policyDigest )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPMS_AUTH_COMMAND cmdAuth;
    TPMS_AUTH_COMMAND *cmdSessionArray[1] = { &cmdAuth };
    TSS2_SYS_CMD_AUTHS cmdAuthArray = { 1, &cmdSessionArray[0] };
    TPM2B_SENSITIVE_CREATE inSensitive;
    TPM2B_PUBLIC inPublic;
    TPM2B_DATA outsideInfo = { { 0, } };
    TPML_PCR_SELECTION creationPcr = { 0 };
    TPM2B_PUBLIC outPublic;
    TPM2B_CREATION_DATA creationData;
    TPM_HANDLE srkHandle;
    TPM2B_DIGEST creationHash;
    TPMT_TK_CREATION creationTicket;
    TPM2B_NAME srkName, blobName;
	TPM2B_DIGEST data;
    TPM2B_PRIVATE outPrivate;

    cmdAuth.sessionHandle = TPM_RS_PW;
    cmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&cmdAuth.sessionAttributes ) ) = 0;
    cmdAuth.hmac.t.size = 0;

    inSensitive.t.sensitive.userAuth.t.size = 0;
    inSensitive.t.sensitive.data.t.size = 0;

    inPublic.t.publicArea.type = TPM_ALG_RSA;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;
    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.restricted = 1;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;
    inPublic.t.publicArea.objectAttributes.decrypt = 1;
    inPublic.t.publicArea.objectAttributes.fixedTPM = 1;
    inPublic.t.publicArea.objectAttributes.fixedParent = 1;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 1;
    inPublic.t.publicArea.authPolicy.t.size = 0;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CBC;
    inPublic.t.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 2048;
    inPublic.t.publicArea.parameters.rsaDetail.exponent = 0;
    inPublic.t.publicArea.unique.rsa.t.size = 0;

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( srkName );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_PLATFORM, &cmdAuthArray,
            &inSensitive, &inPublic, &outsideInfo, &creationPcr,
            &srkHandle, &outPublic, &creationData, &creationHash,
            &creationTicket, &srkName, 0 );
    CheckPassed( rval );

    cmdAuth.sessionHandle = TPM_RS_PW;

    inSensitive.t.sensitive.userAuth.t.size = 0;
    blobAuth.t.size = sizeof( passwordPCRTestPassword );
    memcpy( &blobAuth.t.buffer, passwordPCRTestPassword, sizeof( passwordPCRTestPassword ) );
    CopySizedByteBuffer( &(inSensitive.t.sensitive.userAuth.b ), &blobAuth.b );
    data.t.size = sizeof( dataBlob );
    memcpy( &data.t.buffer, dataBlob, sizeof( dataBlob ) );
    CopySizedByteBuffer( &(inSensitive.t.sensitive.data.b ), &data.b );

    inPublic.t.publicArea.type = TPM_ALG_KEYEDHASH;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA256;
    inPublic.t.publicArea.objectAttributes.restricted = 0;
    inPublic.t.publicArea.objectAttributes.decrypt = 0;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 0;
    CopySizedByteBuffer( &( inPublic.t.publicArea.authPolicy.b), &( policyDigest->b ) );
    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.unique.keyedHash.t.size = 0;

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( outPrivate );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    rval = Tss2_Sys_Create( sysContext, srkHandle, &cmdAuthArray,
            &inSensitive, &inPublic, &outsideInfo, &creationPcr,
            &outPrivate, &outPublic, &creationData, &creationHash,
            &creationTicket, 0 );
    CheckPassed( rval );

    // Now we need to load the object.
    INIT_SIMPLE_TPM2B_SIZE( blobName );
    rval = Tss2_Sys_Load( sysContext, srkHandle, &cmdAuthArray, &outPrivate, &outPublic, &blobHandle, &blobName, 0 );
    CheckPassed( rval );

    return rval;
}

TPM_RC AuthValueUnseal( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPM2B_SENSITIVE_DATA outData;
    TPMS_AUTH_COMMAND cmdAuth;
    TPMS_AUTH_COMMAND *cmdSessionArray[1] = { &cmdAuth };
    TSS2_SYS_CMD_AUTHS cmdAuthArray = { 1, &cmdSessionArray[0] };

    cmdAuth.sessionHandle = policySession->sessionHandle;
    cmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&cmdAuth.sessionAttributes ) ) = 0;
    cmdAuth.sessionAttributes.continueSession = 1;
    cmdAuth.hmac.t.size = 0;

    // Now try to unseal the blob without setting the HMAC.
    // This test should fail.
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_Unseal( sysContext, blobHandle, &cmdAuthArray, &outData, 0 );
    CheckFailed( rval, TPM_RC_S + TPM_RC_1 + TPM_RC_AUTH_FAIL );

    // Clear DA lockout.
    TestDictionaryAttackLockReset();

    //
    // Now try to unseal the blob after setting the HMAC.
    // This test should pass.
    //

    // First, call Prepare.
    rval = Tss2_Sys_Unseal_Prepare( sysContext, blobHandle );
    CheckPassed( rval );

    rval = AddEntity( blobHandle, &blobAuth );
    CheckPassed( rval );

    // Roll nonces for command.
    RollNonces( policySession, &cmdAuth.nonce );

    // Now generate the HMAC.
    rval = ComputeCommandHmacs( sysContext,
            blobHandle,
            TPM_HT_NO_HANDLE, &cmdAuthArray, 1 );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_Unseal( sysContext, blobHandle, &cmdAuthArray, &outData, 0 );
    CheckPassed( rval );

    rval = DeleteEntity( blobHandle );
    CheckPassed( rval );

    // Add test to make sure we unsealed correctly.

    // Now we'll want to flush the data blob and remove it
    // from resource manager tables.
    rval = Tss2_Sys_FlushContext( sysContext, blobHandle );
    CheckPassed( rval );

    return rval;
}

TPM_RC PasswordUnseal( TSS2_SYS_CONTEXT *sysContext, SESSION *policySession )
{
    TPM_RC rval = TPM_RC_SUCCESS;
    TPM2B_SENSITIVE_DATA outData;
    TPMS_AUTH_COMMAND cmdAuth;
    TPMS_AUTH_COMMAND *cmdSessionArray[1] = { &cmdAuth };
    TSS2_SYS_CMD_AUTHS cmdAuthArray = { 1, &cmdSessionArray[0] };

    cmdAuth.sessionHandle = policySession->sessionHandle;
    cmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&cmdAuth.sessionAttributes ) ) = 0;
    cmdAuth.sessionAttributes.continueSession = 1;
    cmdAuth.hmac.t.size = 0;

    // Now try to unseal the blob without setting the password.
    // This test should fail.
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_Unseal( sysContext, blobHandle, &cmdAuthArray, &outData, 0 );
    CheckFailed( rval, TPM_RC_S + TPM_RC_1 + TPM_RC_AUTH_FAIL );

    // Clear DA lockout.
    TestDictionaryAttackLockReset();

    // Now try to unseal the blob after setting the password.
    // This test should pass.
    INIT_SIMPLE_TPM2B_SIZE( outData );
    cmdAuth.hmac.t.size = sizeof( passwordPCRTestPassword );
    memcpy( &cmdAuth.hmac.t.buffer, passwordPCRTestPassword, sizeof( passwordPCRTestPassword ) );
    rval = Tss2_Sys_Unseal( sysContext, blobHandle, &cmdAuthArray, &outData, 0 );
    CheckPassed( rval );

    // Add test to make sure we unsealed correctly.

    // Now we'll want to flush the data blob and remove it
    // from resource manager tables.
    rval = Tss2_Sys_FlushContext( sysContext, blobHandle );
    CheckPassed( rval );

    return rval;
}

POLICY_TEST_SETUP policyTestSetups[] =
{
    // NOTE:  Since locality is a fairly simple command and we
    // can guarantee its correctness, we don't need a trial
    // session for this. buildPolicyFn pointer can be 0 in
    // this case.
    { "LOCALITY", 0, CreateNVIndex, TestLocality },
    { "PASSWORD", BuildPasswordPolicy, CreateDataBlob, PasswordUnseal },
    #ifndef SKIP_PASSWORD_PCR_POLICY_TEST
    { "PASSWORD/PCR", BuildPasswordPcrPolicy, CreateDataBlob, PasswordUnseal },
    #endif
    #ifndef SKIP_AUTH_VALUE_POLICY_TEST
    { "AUTHVALUE", BuildAuthValuePolicy, CreateDataBlob, AuthValueUnseal },
    #endif
    // TBD...
};

void TestPolicy()
{
    UINT32 rval;
    unsigned int i;
    SESSION *policySession = 0;

    DebugPrintf( NO_PREFIX, "\nPOLICY TESTS:\n" );

    for( i = 0; i < ( sizeof( policyTestSetups ) / sizeof( POLICY_TEST_SETUP ) ); i++ )
    {
        TPM2B_DIGEST policyDigest;

        policyDigest.t.size = 0;

        rval = TPM_RC_SUCCESS;

        DebugPrintf( NO_PREFIX, "Policy Test: %s\n", policyTestSetups[i].name );

        // Create trial policy session and run policy commands, in order to create policyDigest.
        if( policyTestSetups[i].buildPolicyFn != 0)
        {
            rval = BuildPolicy( sysContext, &policySession, policyTestSetups[i].buildPolicyFn, &policyDigest, true );
            CheckPassed( rval );
#ifdef DEBUG
            DebugPrintf( NO_PREFIX, "Built policy digest:  \n" );
            DebugPrintBuffer( NO_PREFIX, &(policyDigest.t.buffer[0]), policyDigest.t.size );
#endif
        }

        // Create entity that will use that policyDigest as authPolicy.
        if( policyTestSetups[i].createObjectFn != 0 )
        {
#ifdef DEBUG
            DebugPrintf( NO_PREFIX, "Policy digest used to create object:  \n" );
            DebugPrintBuffer( NO_PREFIX, &(policyDigest.t.buffer[0]), policyDigest.t.size );
#endif

            rval = ( *policyTestSetups[i].createObjectFn )( sysContext, &policySession, &policyDigest);
            CheckPassed( rval );
        }

        // Create real policy session and run policy commands; after this we're ready
        // to authorize actions on the entity.
        if( policyTestSetups[i].buildPolicyFn != 0)
        {
            rval = BuildPolicy( sysContext, &policySession, policyTestSetups[i].buildPolicyFn, &policyDigest, false );
            CheckPassed( rval );
#ifdef DEBUG
            DebugPrintf( NO_PREFIX, "Command policy digest:  \n" );
            DebugPrintBuffer( NO_PREFIX, &(policyDigest.t.buffer[0]), policyDigest.t.size );
#endif
        }

        if( policySession )
        {
            // Now do tests by authorizing actions on the entity.
            rval = ( *policyTestSetups[i].testPolicyFn)( sysContext, policySession );
            CheckPassed( rval );

            // Need to flush the session here.
            rval = Tss2_Sys_FlushContext( sysContext, policySession->sessionHandle );
            CheckPassed( rval );

            // And remove the session from test app session table.
            rval = EndAuthSession( policySession );
        }
        else
        {
            CheckFailed( rval, 0xffffffff );
        }

        CheckPassed( rval );
    }
}

#define MAX_TEST_SEQUENCES 10
void TestHash()
{
    UINT32 rval;
    TPM2B_AUTH      auth;
    TPMI_DH_OBJECT  sequenceHandle[MAX_TEST_SEQUENCES];
    TPMS_AUTH_COMMAND sessionData, sessionData1;
    TPMS_AUTH_RESPONSE sessionDataOut, sessionDataOut1;
    TSS2_SYS_CMD_AUTHS sessionsData;
    int i;
    TPM2B_MAX_BUFFER dataToHash;

    UINT8           memoryToHash[] =
    {
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
          0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
          0xde, 0xad, 0xbe, 0xef
    };

    // Known good hash of above memory.
    UINT8           goodHashValue[] =
            { 0xB3, 0xFD, 0x6A, 0xD2, 0x9F, 0xD0, 0x13, 0x52, 0xBA, 0xFC,
              0x8B, 0x22, 0xC9, 0x6D, 0x88, 0x42, 0xA3, 0x3C, 0xB0, 0xC9 };

    // Hash to be calculated by TPM.
    TPM2B_DIGEST result;
    TPMT_TK_HASHCHECK validation;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;

    TPMS_AUTH_COMMAND *sessionDataArray[2];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[2];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;
    sessionDataArray[1] = &sessionData1;
    sessionDataOutArray[1] = &sessionDataOut1;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nHASH TESTS:\n" );

    auth.t.size = 2;
    auth.t.buffer[0] = 0;
    auth.t.buffer[1] = 0xff;
    rval = Tss2_Sys_HashSequenceStart ( sysContext, 0, &auth, TPM_ALG_SHA1, &sequenceHandle[0], 0 );
    CheckPassed( rval );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac = auth;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    dataToHash.t.size = MAX_DIGEST_BUFFER;
    memcpy( &dataToHash.t.buffer[0], &memoryToHash[0], dataToHash.t.size );

    rval = Tss2_Sys_SequenceUpdate ( sysContext, sequenceHandle[0], &sessionsData, &dataToHash, &sessionsDataOut );
    CheckPassed( rval );

    // Now try starting a bunch of sequences to see what happens.
    // This checks that the resource manager properly saves and restores the context
    // of the interrupted original sequence.
    for( i = 1; i < 5; i++ )
    {
        rval = Tss2_Sys_HashSequenceStart ( sysContext, 0, &auth, TPM_ALG_SHA1, &sequenceHandle[i], 0 );
        CheckPassed( rval );
    }

    // Now end the created sequences.
    dataToHash.t.size = 0;
    for( i = 1; i < 5; i++ )
    {
        INIT_SIMPLE_TPM2B_SIZE( result );
        rval = Tss2_Sys_SequenceComplete ( sysContext, sequenceHandle[i], &sessionsData, &dataToHash,
                TPM_RH_PLATFORM, &result, &validation, &sessionsDataOut );
        CheckPassed( rval );
    }

    //  Now try to finish the interrupted sequence.
    rval = Tss2_Sys_SequenceUpdate ( sysContext, sequenceHandle[0], &sessionsData, &dataToHash, &sessionsDataOut );
    CheckPassed( rval );

    dataToHash.t.size = sizeof( memoryToHash ) - MAX_DIGEST_BUFFER;
    memcpy( &dataToHash.t.buffer[0], &memoryToHash[MAX_DIGEST_BUFFER], dataToHash.t.size );
    INIT_SIMPLE_TPM2B_SIZE( result );
    rval = Tss2_Sys_SequenceComplete ( sysContext, sequenceHandle[0], &sessionsData, &dataToHash,
            TPM_RH_PLATFORM, &result, &validation, &sessionsDataOut );
    CheckPassed( rval );

    // Test the resulting hash.
    if( memcmp( (void *)&( result.t.buffer[0] ), (void *)&( goodHashValue[0] ), result.t.size ) )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! resulting hash is incorrect.\n" );
        Cleanup();
    }

    // Now try starting a bunch of sequences to see what happens.
    // This stresses the resource manager.
    for( i = 0; i < MAX_TEST_SEQUENCES; i++ )
    {
        rval = Tss2_Sys_HashSequenceStart ( sysContext, 0, &auth, TPM_ALG_SHA1, &sequenceHandle[i], 0 );
        CheckPassed( rval );
    }

    // Now end them all
    dataToHash.t.size = 0;
    for( i = (MAX_TEST_SEQUENCES - 1); i >= 0; i-- )
//    for( i = 0; i < MAX_TEST_SEQUENCES; i++ )
    {
        INIT_SIMPLE_TPM2B_SIZE( result );
        rval = Tss2_Sys_SequenceComplete ( sysContext, sequenceHandle[i], &sessionsData, &dataToHash,
                TPM_RH_PLATFORM, &result, &validation, &sessionsDataOut );
        CheckPassed( rval );
    }
}

void TestQuote()
{
    UINT32 rval;
    TPM2B_DATA qualifyingData;
    UINT8 qualDataString[] = { 0x00, 0xff, 0x55, 0xaa };
    TPMT_SIG_SCHEME inScheme;
    TPML_PCR_SELECTION  pcrSelection;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    TPM2B_ATTEST quoted;
    TPMT_SIGNATURE signature;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nQUOTE CONTROL TESTS:\n" );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 2;
    sessionData.hmac.t.buffer[0] = 0x00;
    sessionData.hmac.t.buffer[1] = 0xff;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    qualifyingData.t.size = sizeof( qualDataString );
    memcpy( &( qualifyingData.t.buffer[0] ), qualDataString, sizeof( qualDataString ) );

    inScheme.scheme = TPM_ALG_NULL;

    pcrSelection.count = 1;
    pcrSelection.pcrSelections[0].hash = TPM_ALG_SHA1;
    pcrSelection.pcrSelections[0].sizeofSelect = 3;

    // Clear out PCR select bit field
    pcrSelection.pcrSelections[0].pcrSelect[0] = 0;
    pcrSelection.pcrSelections[0].pcrSelect[1] = 0;
    pcrSelection.pcrSelections[0].pcrSelect[2] = 0;

    // Now set the PCR you want
    pcrSelection.pcrSelections[0].pcrSelect[( PCR_17/8 )] = ( 1 << ( PCR_18 % 8) );

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    // Test with wrong type of key.
    INIT_SIMPLE_TPM2B_SIZE( quoted );
    rval = Tss2_Sys_Quote ( sysContext, loadedSha1KeyHandle, &sessionsData, &qualifyingData, &inScheme,
            &pcrSelection,  &quoted, &signature, &sessionsDataOut );
    CheckPassed( rval );

    // Create signing key


    // Now test quote operation
//    Tpm20Quote ( ??TPMI_DH_OBJECT signHandle, TPM2B_DATA *qualifyingData,
//    TPMT_SIG_SCHEME *inScheme, TPML_PCR_SELECTION *pcrSelect,
//    TPMS_AUTH_COMMAND *sessionsData)

}

void ProvisionOtherIndices()
{
    UINT32 rval;
    TPMI_SH_AUTH_SESSION otherIndicesPolicyAuthHandle;
    TPM2B_DIGEST  nvPolicyHash;
    TPM2B_AUTH  nvAuth;
    TPMS_AUTH_COMMAND otherIndicesSessionData;
    TPMS_AUTH_RESPONSE otherIndicesSessionDataOut;
    TSS2_SYS_CMD_AUTHS otherIndicesSessionsData;
    TSS2_SYS_RSP_AUTHS otherIndicesSessionsDataOut;
    TPM2B_NV_PUBLIC publicInfo;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &otherIndicesSessionData;
    sessionDataOutArray[0] = &otherIndicesSessionDataOut;

    otherIndicesSessionsDataOut.rspAuths = &sessionDataOutArray[0];
    otherIndicesSessionsData.cmdAuths = &sessionDataArray[0];

    otherIndicesSessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nPROVISION OTHER NV INDICES:\n" );

    //
    // AUX index: Write is controlled by TPM2_PolicyLocality; Read is controlled by authValue and is unrestricted since authValue is set to emptyBuffer
    // Do this by setting up two policies and ORing them together when creating AuxIndex:
    // 1.  PolicyLocality(3) && PolicyCommand(NVWrite)
    // 2.  EmptyAuth policy && PolicyCommand(NVRead)
    // Page 126 of Part 1 describes how to do this.
    //

    // Steps:
    rval = StartPolicySession( &otherIndicesPolicyAuthHandle );
    CheckPassed( rval );

    // 3.  GetPolicyDigest and save it
    INIT_SIMPLE_TPM2B_SIZE( nvPolicyHash );
    rval = Tss2_Sys_PolicyGetDigest( sysContext, otherIndicesPolicyAuthHandle, 0, &nvPolicyHash, 0 );
    CheckPassed( rval );

    // Now save the policy digest from the first OR branch.
    DEBUG_PRINT_BUFFER( NO_PREFIX, &( nvPolicyHash.t.buffer[0] ), nvPolicyHash.t.size );

    // 4.  CreateNvIndex
    otherIndicesSessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    otherIndicesSessionData.nonce.t.size = 0;

    // init hmac
    otherIndicesSessionData.hmac.t.size = 0;

    // init nvAuth
    nvAuth.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&otherIndicesSessionData.sessionAttributes ) ) = 0;

    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
            sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
            sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = INDEX_LCP_SUP;
    publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA1;

    // First zero out attributes.
    *(UINT32 *)&( publicInfo.t.nvPublic.attributes ) = 0;

    // Now set the attributes.
    publicInfo.t.nvPublic.attributes.TPMA_NV_AUTHREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_AUTHWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 1;
    // Following commented out for convenience during development.
    // publicInfo.t.nvPublic.attributes.TPMA_NV_POLICY_DELETE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_WRITEDEFINE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_ORDERLY = 1;

    publicInfo.t.nvPublic.authPolicy.t.size = 0;
    publicInfo.t.nvPublic.dataSize = NV_PS_INDEX_SIZE;

    otherIndicesSessionsData.cmdAuthsCount = 1;
    otherIndicesSessionsData.cmdAuths[0] = &otherIndicesSessionData;

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &otherIndicesSessionsData,
            &nvAuth, &publicInfo, &otherIndicesSessionsDataOut );
    CheckPassed( rval );

    publicInfo.t.nvPublic.nvIndex = INDEX_LCP_OWN;
    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &otherIndicesSessionsData,
            &nvAuth, &publicInfo, &otherIndicesSessionsDataOut );
    CheckPassed( rval );

    // Now teardown session
    rval = Tss2_Sys_FlushContext( sysContext, otherIndicesPolicyAuthHandle );
    CheckPassed( rval );
}


TSS2_RC InitNvAuxPolicySession( TPMI_SH_AUTH_SESSION *nvAuxPolicySessionHandle )
{
    TPMA_LOCALITY locality;
    TPM_RC rval;

    rval = StartPolicySession( nvAuxPolicySessionHandle );
    CheckPassed( rval );

    // 2.  PolicyLocality(3)
    *(UINT8 *)((void *)&locality) = 0;
    locality.TPM_LOC_THREE = 1;
    locality.TPM_LOC_FOUR = 1;
    rval = Tss2_Sys_PolicyLocality( sysContext, *nvAuxPolicySessionHandle, 0, locality, 0 );

    return( rval );
}

void ProvisionNvAux()
{
    UINT32 rval;
    TPMI_SH_AUTH_SESSION nvAuxPolicyAuthHandle;
    TPM2B_DIGEST  nvPolicyHash;
    TPM2B_AUTH  nvAuth;
    TPMS_AUTH_COMMAND nvAuxSessionData;
    TPMS_AUTH_RESPONSE nvAuxSessionDataOut;
    TSS2_SYS_CMD_AUTHS nvAuxSessionsData;
    TSS2_SYS_RSP_AUTHS nvAuxSessionsDataOut;
    TPM2B_NV_PUBLIC publicInfo;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &nvAuxSessionData;
    sessionDataOutArray[0] = &nvAuxSessionDataOut;

    nvAuxSessionsDataOut.rspAuths = &sessionDataOutArray[0];
    nvAuxSessionsData.cmdAuths = &sessionDataArray[0];

    nvAuxSessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nPROVISION NV AUX:\n" );

    //
    // AUX index: Write is controlled by TPM2_PolicyLocality; Read is controlled by authValue and is unrestricted since authValue is set to emptyBuffer
    // Do this by setting up two policies and ORing them together when creating AuxIndex:
    // 1.  PolicyLocality(3) && PolicyCommand(NVWrite)
    // 2.  EmptyAuth policy && PolicyCommand(NVRead)
    // Page 126 of Part 1 describes how to do this.
    //

    // Steps:
    rval = InitNvAuxPolicySession( &nvAuxPolicyAuthHandle );
    CheckPassed( rval );

    // 3.  GetPolicyDigest and save it
    INIT_SIMPLE_TPM2B_SIZE( nvPolicyHash );
    rval = Tss2_Sys_PolicyGetDigest( sysContext, nvAuxPolicyAuthHandle, 0, &nvPolicyHash, 0 );
    CheckPassed( rval );

    // Now save the policy digest.
    DEBUG_PRINT_BUFFER( NO_PREFIX, &( nvPolicyHash.t.buffer[0] ), nvPolicyHash.t.size );

    // 4.  CreateNvIndex
    nvAuxSessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    nvAuxSessionData.nonce.t.size = 0;

    // init hmac
    nvAuxSessionData.hmac.t.size = 0;

    // init nvAuth
    nvAuth.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&nvAuxSessionData.sessionAttributes ) ) = 0;

    nvAuxSessionsData.cmdAuthsCount = 1;
    nvAuxSessionsData.cmdAuths[0] = &nvAuxSessionData;

    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
            sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
            sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = INDEX_AUX;
    publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA1;

    // First zero out attributes.
    *(UINT32 *)&( publicInfo.t.nvPublic.attributes ) = 0;

    // Now set the attributes.
    publicInfo.t.nvPublic.attributes.TPMA_NV_AUTHREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_POLICYWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 1;
    // Following commented out for convenience during development.
    // publicInfo.t.nvPublic.attributes.TPMA_NV_POLICY_DELETE = 1;

    publicInfo.t.nvPublic.authPolicy.t.size = GetDigestSize( TPM_ALG_SHA1 );
    memcpy( (UINT8 *)&( publicInfo.t.nvPublic.authPolicy.t.buffer ), (UINT8 *)&(nvPolicyHash.t.buffer[0]),
            nvPolicyHash.t.size );

    publicInfo.t.nvPublic.dataSize = NV_AUX_INDEX_SIZE;

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM, &nvAuxSessionsData,
            &nvAuth, &publicInfo, &nvAuxSessionsDataOut );
    CheckPassed( rval );

    // Now teardown session
    rval = Tss2_Sys_FlushContext( sysContext, nvAuxPolicyAuthHandle );
    CheckPassed( rval );
}

void TpmAuxWrite( int locality)
{
    TSS2_RC rval;
    int i;
    TPMI_SH_AUTH_SESSION nvAuxPolicyAuthHandle;
    TPM2B_MAX_NV_BUFFER nvWriteData;

    rval = InitNvAuxPolicySession( &nvAuxPolicyAuthHandle );
    CheckPassed( rval );

    // Now we're going to test it.
    nvWriteData.t.size = 4;
    for( i = 0; i < nvWriteData.t.size; i++ )
        nvWriteData.t.buffer[i] = 0xff - i;

    nullSessionData.sessionHandle = nvAuxPolicyAuthHandle;

    // Make sure that session terminates after NVWrite completes.
    nullSessionData.sessionAttributes.continueSession = 0;

    rval = SetLocality( sysContext, locality );
    CheckPassed( rval );

    nullSessionsData.cmdAuthsCount = 1;
    nullSessionsData.cmdAuths[0] = &nullSessionData;

    rval = Tss2_Sys_NV_Write( sysContext, INDEX_AUX, INDEX_AUX, &nullSessionsData, &nvWriteData, 0, &nullSessionsDataOut );

    {
        TSS2_RC setLocalityRval;
        setLocalityRval = SetLocality( sysContext, 3 );
        CheckPassed( setLocalityRval );
    }

    if( locality == 3 || locality == 4 )
    {
        CheckPassed( rval );

        // No teardown of session needed, since the authorization was
        // successful.
    }
    else
    {
        CheckFailed( rval, TPM_RC_LOCALITY );

        // Now teardown session
        rval = Tss2_Sys_FlushContext( sysContext, nvAuxPolicyAuthHandle );
        CheckPassed( rval );
    }
}

void TpmAuxReadWriteTest()
{
    UINT32 rval;
    int testLocality;
    TPM2B_MAX_NV_BUFFER nvData;

    DebugPrintf( NO_PREFIX, "TPM AUX READ/WRITE TEST\n" );

    nullSessionData.sessionAttributes.continueSession = 0;

    // Try writing it from all localities.  Only locality 3 should work.
    for( testLocality = 0; testLocality < 5; testLocality++ )
    {
        TpmAuxWrite( testLocality );
    }

    nullSessionData.sessionHandle = TPM_RS_PW;

    nullSessionsData.cmdAuths[0] = &nullSessionData;

    // Try reading it from all localities.  They all should work.
    for( testLocality = 0; testLocality < 5; testLocality++ )
    {
        rval = SetLocality( sysContext, testLocality );
        CheckPassed( rval );

        INIT_SIMPLE_TPM2B_SIZE( nvData );
        rval = TSS2_RETRY_EXP( Tss2_Sys_NV_Read( sysContext, INDEX_AUX, INDEX_AUX, &nullSessionsData, 4, 0, &nvData, &nullSessionsDataOut ));
        CheckPassed( rval );

        rval = SetLocality( sysContext, 3 );
        CheckPassed( rval );
    }
}

void TpmOtherIndicesReadWriteTest()
{
    UINT32 rval;
    TPM2B_MAX_NV_BUFFER nvWriteData;
    int i;
    TPM2B_MAX_NV_BUFFER nvData;

    nullSessionData.sessionHandle = TPM_RS_PW;

    DebugPrintf( NO_PREFIX, "TPM OTHER READ/WRITE TEST\n" );

    nvWriteData.t.size = 4;
    for( i = 0; i < nvWriteData.t.size; i++ )
        nvWriteData.t.buffer[i] = 0xff - i;

    nullSessionsData.cmdAuthsCount = 1;
    nullSessionsData.cmdAuths[0] = &nullSessionData;

    rval = Tss2_Sys_NV_Write( sysContext, INDEX_LCP_SUP, INDEX_LCP_SUP, &nullSessionsData, &nvWriteData, 0, &nullSessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_Write( sysContext, INDEX_LCP_OWN, INDEX_LCP_OWN, &nullSessionsData, &nvWriteData, 0, &nullSessionsDataOut );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, INDEX_LCP_SUP, INDEX_LCP_SUP, &nullSessionsData, 4, 0, &nvData, &nullSessionsDataOut );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( nvData );
    rval = Tss2_Sys_NV_Read( sysContext, INDEX_LCP_OWN, INDEX_LCP_OWN, &nullSessionsData, 4, 0, &nvData, &nullSessionsDataOut );
    CheckPassed( rval );
}

void NvIndexProto()
{
    UINT32 rval;

    DebugPrintf( NO_PREFIX, "\nNV INDEX PROTOTYPE TESTS:\n" );


    // AUX index: Write is controlled by TPM2_PolicyLocality; Read is controlled by authValue and is unrestricted since authValue is set to emptyBuffer
    // PS index: Write and read are unrestricted until TPM2_WriteLock. After that content is write protected
    // PO index: Write is restricted by ownerAuth; Read is controlled by authValue and is unrestricted since authValue is set to emptyBuffer

    // Now we need to configure NV indices
    ProvisionNvAux();

    ProvisionOtherIndices();

    TpmAuxReadWriteTest();

    TpmOtherIndicesReadWriteTest();

    // Now undefine the aux index, so that subsequent test passes will work.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, INDEX_AUX, &nullSessionsData, &nullSessionsDataOut );
    CheckPassed( rval );

    // Now undefine the other indices, so that subsequent test passes will work.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, INDEX_LCP_SUP, &nullSessionsData, &nullSessionsDataOut );
    CheckPassed( rval );

    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, INDEX_LCP_OWN, &nullSessionsData, &nullSessionsDataOut );
    CheckPassed( rval );
}

void TestPcrAllocate()
{
    UINT32 rval;
    TPML_PCR_SELECTION  pcrSelection;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    TPMI_YES_NO allocationSuccess;
    UINT32 maxPcr;
    UINT32 sizeNeeded;
    UINT32 sizeAvailable;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    DebugPrintf( NO_PREFIX, "\nPCR ALLOCATE TEST  :\n" );

    // Init authHandle
    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    pcrSelection.count = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    rval = Tss2_Sys_PCR_Allocate( sysContext, TPM_RH_PLATFORM, &sessionsData, &pcrSelection,
            &allocationSuccess, &maxPcr, &sizeNeeded, &sizeAvailable, &sessionsDataOut);
    CheckPassed( rval );

    pcrSelection.count = 3;
    pcrSelection.pcrSelections[0].hash = TPM_ALG_SHA256;
    CLEAR_PCR_SELECT_BITS( pcrSelection.pcrSelections[0] );
    SET_PCR_SELECT_SIZE( pcrSelection.pcrSelections[0], 3 );
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[0], PCR_5 );
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[0], PCR_7 );
    pcrSelection.pcrSelections[1].hash = TPM_ALG_SHA384;
    CLEAR_PCR_SELECT_BITS( pcrSelection.pcrSelections[1] );
    SET_PCR_SELECT_SIZE( pcrSelection.pcrSelections[1], 3 );
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[1], PCR_5 );
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[1], PCR_8 );
    pcrSelection.pcrSelections[2].hash = TPM_ALG_SHA256;
    CLEAR_PCR_SELECT_BITS( pcrSelection.pcrSelections[2] );
    SET_PCR_SELECT_SIZE( pcrSelection.pcrSelections[2], 3 );
    SET_PCR_SELECT_BIT( pcrSelection.pcrSelections[2], PCR_6 );

    rval = Tss2_Sys_PCR_Allocate( sysContext, TPM_RH_PLATFORM, &sessionsData, &pcrSelection,
            &allocationSuccess, &maxPcr, &sizeNeeded, &sizeAvailable, &sessionsDataOut);
    CheckPassed( rval );
}

void TestUnseal()
{
    UINT32 rval;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    TPM2B_SENSITIVE_CREATE  inSensitive;
    TPML_PCR_SELECTION      creationPCR;
    TPM2B_DATA              outsideInfo;
    TPM2B_PUBLIC            inPublic;
    TPM_HANDLE loadedObjectHandle;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    TPM2B_PRIVATE outPrivate;
    TPM2B_PUBLIC outPublic;
    TPM2B_CREATION_DATA creationData;
    TPM2B_DIGEST creationHash;
    TPMT_TK_CREATION creationTicket;
    TPM2B_NAME name;
    TPM2B_SENSITIVE_DATA outData;


    const char authStr[] = "test";
    const char sensitiveData[] = "this is sensitive";

    DebugPrintf( NO_PREFIX, "\nUNSEAL TEST  :\n" );

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    sessionData.hmac.t.size = 2;
    sessionData.hmac.t.buffer[0] = 0x00;
    sessionData.hmac.t.buffer[1] = 0xff;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    inSensitive.t.sensitive.userAuth.t.size = sizeof( authStr ) - 1;
    memcpy( &( inSensitive.t.sensitive.userAuth.t.buffer[0] ), authStr, sizeof( authStr ) - 1 );
    inSensitive.t.sensitive.data.t.size = sizeof( sensitiveData ) - 1;
    memcpy( &( inSensitive.t.sensitive.data.t.buffer[0] ), sensitiveData, sizeof( sensitiveData ) - 1 );

    inPublic.t.publicArea.authPolicy.t.size = 0;

    inPublic.t.publicArea.unique.keyedHash.t.size = 0;

    outsideInfo.t.size = 0;
    creationPCR.count = 0;

    inPublic.t.publicArea.type = TPM_ALG_KEYEDHASH;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;

    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;

    inPublic.t.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;

    inPublic.t.publicArea.unique.keyedHash.t.size = 0;

    outsideInfo.t.size = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0]  = &sessionData;

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( outPrivate );
    rval = Tss2_Sys_Create( sysContext, handle2048rsa, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR,
            &outPrivate, &outPublic, &creationData,
            &creationHash, &creationTicket, &sessionsDataOut );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_LoadExternal ( sysContext, 0, 0, &outPublic,
            TPM_RH_PLATFORM, &loadedObjectHandle, &name, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_FlushContext( sysContext, loadedObjectHandle );
    CheckPassed( rval );

    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_Load ( sysContext, handle2048rsa, &sessionsData, &outPrivate, &outPublic,
            &loadedObjectHandle, &name, &sessionsDataOut);
    CheckPassed( rval );

    sessionData.hmac.t.size = sizeof( authStr ) - 1;
    memcpy( &( sessionData.hmac.t.buffer[0] ), authStr, sizeof( authStr ) - 1 );

    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_Unseal( sysContext, loadedObjectHandle, &sessionsData, &outData, &sessionsDataOut );

    rval = Tss2_Sys_FlushContext( sysContext, loadedObjectHandle );
    CheckPassed( rval );

    CheckPassed( rval );
}


void CreatePasswordTestNV( TPMI_RH_NV_INDEX nvIndex, char * password )
{
    UINT32 rval;
    int i;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;
    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    TPM2B_NV_PUBLIC publicInfo;
    TPM2B_AUTH  nvAuth;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsDataOut.rspAuthsCount = 1;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    nvAuth.t.size = strlen( password );
    for( i = 0; i < nvAuth.t.size; i++ )
        nvAuth.t.buffer[i] = password[i];

    publicInfo.t.size = sizeof( TPMI_RH_NV_INDEX ) +
        sizeof( TPMI_ALG_HASH ) + sizeof( TPMA_NV ) + sizeof( UINT16) +
        sizeof( UINT16 );
    publicInfo.t.nvPublic.nvIndex = nvIndex;
    publicInfo.t.nvPublic.nameAlg = TPM_ALG_SHA1;

    // First zero out attributes.
    *(UINT32 *)&( publicInfo.t.nvPublic.attributes ) = 0;

    // Now set the attributes.
    publicInfo.t.nvPublic.attributes.TPMA_NV_AUTHREAD = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_AUTHWRITE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_PLATFORMCREATE = 1;
    publicInfo.t.nvPublic.attributes.TPMA_NV_ORDERLY = 1;
    publicInfo.t.nvPublic.authPolicy.t.size = 0;
    publicInfo.t.nvPublic.dataSize = 32;

    rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM_RH_PLATFORM,
            &sessionsData, &nvAuth, &publicInfo, &sessionsDataOut );
    CheckPassed( rval );
}

// Password used to authorize access to the NV index.
char password[] = "test password";

void PasswordTest()
{
    UINT32 rval;
    int i;

    // Authorization structure for command.
    TPMS_AUTH_COMMAND sessionData;

    // Authorization structure for response.
    TPMS_AUTH_RESPONSE sessionDataOut;

    // Create and init authorization area for command:
    // only 1 authorization area.
    TPMS_AUTH_COMMAND *sessionDataArray[1] = { &sessionData };

    // Create authorization area for response:
    // only 1 authorization area.
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1] = { &sessionDataOut };

    // Authorization array for command (only has one auth structure).
    TSS2_SYS_CMD_AUTHS sessionsData = { 1, &sessionDataArray[0] };

    // Authorization array for response (only has one auth structure).
    TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, &sessionDataOutArray[0] };
    TPM2B_MAX_NV_BUFFER nvWriteData;

    DebugPrintf( NO_PREFIX, "\nPASSWORD TESTS:\n" );

    // Create an NV index that will use password
    // authorizations the password will be
    // "test password".
    CreatePasswordTestNV( TPM20_INDEX_PASSWORD_TEST, password );

    //
    // Initialize the command authorization area.
    //

    // Init sessionHandle, nonce, session
    // attributes, and hmac (password).
    sessionData.sessionHandle = TPM_RS_PW;
    // Set zero sized nonce.
    sessionData.nonce.t.size = 0;
    // sessionAttributes is a bit field.  To initialize
    // it to 0, cast to a pointer to UINT8 and
    // write 0 to that pointer.
    *( (UINT8 *)&sessionData.sessionAttributes ) = 0;

    // Init password (HMAC field in authorization structure).
    sessionData.hmac.t.size = strlen( password );
    memcpy( &( sessionData.hmac.t.buffer[0] ),
            &( password[0] ), sessionData.hmac.t.size );

    // Initialize write data.
    nvWriteData.t.size = 4;
    for( i = 0; i < nvWriteData.t.size; i++ )
        nvWriteData.t.buffer[i] = 0xff - i;

    // Attempt write with the correct password.
    // It should pass.
    rval = Tss2_Sys_NV_Write( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &sessionsData, &nvWriteData, 0,
            &sessionsDataOut );
    // Check that the function passed as
    // expected.  Otherwise, exit.
    CheckPassed( rval );

    // Alter the password so it's incorrect.
    sessionData.hmac.t.buffer[4] = 0xff;
    rval = Tss2_Sys_NV_Write( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &sessionsData, &nvWriteData, 0,
            &sessionsDataOut );
    // Check that the function failed as expected,
    // since password was incorrect.  If wrong
    // response code received, exit.
    CheckFailed( rval,
            TPM_RC_S + TPM_RC_1 + TPM_RC_AUTH_FAIL );

    // Change hmac to null one, since null auth is
    // used to undefine the index.
    sessionData.hmac.t.size = 0;

    // Now undefine the index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM,
            TPM20_INDEX_PASSWORD_TEST, &sessionsData, 0 );
    CheckPassed( rval );
}


void SimplePolicyTest()
{
    UINT32 rval, sessionCmdRval;
    TPM2B_AUTH  nvAuth;
    SESSION *nvSession, *trialPolicySession;
    TPMA_NV nvAttributes;
    TPM2B_DIGEST authPolicy;
    TPM2B_NAME nvName;
    TPM2B_MAX_NV_BUFFER nvWriteData, nvReadData;
    UINT8 dataToWrite[] = { 0x00, 0xff, 0x55, 0xaa };
    int i;
    TPM2B_ENCRYPTED_SECRET encryptedSalt;
    TPMT_SYM_DEF symmetric;
    TPMA_SESSION sessionAttributes;

    // Command authorization area: one password session.
    TPMS_AUTH_COMMAND nvCmdAuth = { TPM_RS_PW, };
    TPMS_AUTH_COMMAND *nvCmdAuthArray[1] = { &nvCmdAuth };
    TSS2_SYS_CMD_AUTHS nvCmdAuths = { 1, &nvCmdAuthArray[0] };

    // Response authorization area.
    TPMS_AUTH_RESPONSE nvRspAuth;
    TPMS_AUTH_RESPONSE *nvRspAuthArray[1] = { &nvRspAuth };
    TSS2_SYS_RSP_AUTHS nvRspAuths = { 1, &nvRspAuthArray[0] };
    TPM_ALG_ID sessionAlg = TPM_ALG_SHA256;
    TPM2B_NONCE nonceCaller;

    nonceCaller.t.size = 0;

    DebugPrintf( NO_PREFIX, "\nSIMPLE POLICY TEST:\n" );

    //
    // Create NV index.
    //

    // Setup the NV index's authorization value.
    nvAuth.t.size = 0;

    // Zero sized encrypted salt, since the session
    // is unsalted.
    encryptedSalt.t.size = 0;

    // No symmetric algorithm.
    symmetric.algorithm = TPM_ALG_NULL;

    //
    // Create the NV index's authorization policy
    // using a trial policy session.
    //
    rval = StartAuthSessionWithParams( &trialPolicySession, TPM_RH_NULL,
            0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM_SE_TRIAL,
            &symmetric, sessionAlg, resMgrTctiContext );
    CheckPassed( rval );

    rval = Tss2_Sys_PolicyAuthValue( sysContext, trialPolicySession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    // Get policy digest.
    INIT_SIMPLE_TPM2B_SIZE( authPolicy );
    rval = Tss2_Sys_PolicyGetDigest( sysContext, trialPolicySession->sessionHandle,
            0, &authPolicy, 0 );
    CheckPassed( rval );

    // End the trial session by flushing it.
    rval = Tss2_Sys_FlushContext( sysContext, trialPolicySession->sessionHandle );
    CheckPassed( rval );

    // And remove the trial policy session from sessions table.
    rval = EndAuthSession( trialPolicySession );
    CheckPassed( rval );

    // Now set the NV index's attributes:
    // policyRead, authWrite, and platormCreate.
    *(UINT32 *)( (void *)&nvAttributes ) = 0;
    nvAttributes.TPMA_NV_POLICYREAD = 1;
    nvAttributes.TPMA_NV_POLICYWRITE = 1;
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    // Create the NV index.
    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW,
            &nvAuth, &authPolicy, TPM20_INDEX_PASSWORD_TEST,
            sessionAlg, nvAttributes, 32  );
    CheckPassed( rval );

    // Add index and associated authorization value to
    // entity table.  This helps when we need
    // to calculate HMACs.
    AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );
    CheckPassed( rval );

    // Get the name of the NV index.
    rval = (*HandleToNameFunctionPtr)( TPM20_INDEX_PASSWORD_TEST,
            &nvName );
    CheckPassed( rval );

    //
    // Start real (non-trial) policy authorization session:
    // it's an unbound and unsalted session, no symmetric
    // encryption algorithm, and SHA256 is the session's
    // hash algorithm.
    //

    // Zero sized encrypted salt, since the session
    // is unsalted.
    encryptedSalt.t.size = 0;

    // No symmetric algorithm.
    symmetric.algorithm = TPM_ALG_NULL;

    // Create the session.
    // Session state (session handle, nonces, etc.) gets
    // saved into nvSession structure for later use.
    rval = StartAuthSessionWithParams( &nvSession, TPM_RH_NULL,
            0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM_SE_POLICY,
            &symmetric, sessionAlg, resMgrTctiContext );
    CheckPassed( rval );

    // Get the name of the session and save it in
    // the nvSession structure.
    rval = (*HandleToNameFunctionPtr)( nvSession->sessionHandle,
            &nvSession->name );
    CheckPassed( rval );

    // Initialize NV write data.
    nvWriteData.t.size = sizeof( dataToWrite );
    for( i = 0; i < nvWriteData.t.size; i++ )
    {
        nvWriteData.t.buffer[i] = dataToWrite[i];
    }

    //
    // Now setup for writing the NV index.
    //

    rval = Tss2_Sys_PolicyAuthValue( sysContext, nvSession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    // Get policy digest.
    INIT_SIMPLE_TPM2B_SIZE( authPolicy );
    rval = Tss2_Sys_PolicyGetDigest( sysContext, trialPolicySession->sessionHandle,
            0, &authPolicy, 0 );
    CheckPassed( rval );

    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Write_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
    CheckPassed( rval );

    // Configure command authorization area, except for HMAC.
    nvCmdAuths.cmdAuths[0]->sessionHandle = nvSession->sessionHandle;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 1;
    nvCmdAuths.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
    *( (UINT8 *)((void *)&sessionAttributes ) ) = 0;
    nvCmdAuths.cmdAuths[0]->sessionAttributes = sessionAttributes;
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 1;

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // Finally!!  Write the data to the NV index.
    // If the command is successful, the command
    // HMAC was correct.
    sessionCmdRval = Tss2_Sys_NV_Write( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, &nvWriteData, 0, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( sysContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    rval = Tss2_Sys_PolicyAuthValue( sysContext, nvSession->sessionHandle, 0, 0 );
    CheckPassed( rval );

    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Read_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, sizeof( dataToWrite ), 0 );
    CheckPassed( rval );

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // End the session after next command.
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 0;

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // And now read the data back.
    // If the command is successful, the command
    // HMAC was correct.
    INIT_SIMPLE_TPM2B_SIZE( nvReadData );
    sessionCmdRval = Tss2_Sys_NV_Read( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, sizeof( dataToWrite ), 0,
            &nvReadData, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( sysContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    // Check that write and read data are equal.
    if( memcmp( (void *)&nvReadData.t.buffer[0],
            (void *)&nvWriteData.t.buffer[0], nvReadData.t.size ) )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! read data not equal to written data\n" );
        Cleanup();
    }

    //
    // Now cleanup:  undefine the NV index and delete
    // the NV index's entity table entry.
    //

    // Setup authorization for undefining the NV index.
    nvCmdAuths.cmdAuths[0]->sessionHandle = TPM_RS_PW;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 0;
    nvCmdAuths.cmdAuths[0]->hmac.t.size = 0;

    // Undefine the NV index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext,
            TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, 0 );
    CheckPassed( rval );

    // Delete the NV index's entry in the entity table.
    rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );
    CheckPassed( rval );
}

void SimpleHmacTest()
{
    UINT32 rval, sessionCmdRval;
    TPM2B_AUTH  nvAuth;
    SESSION *nvSession;
    TPMA_NV nvAttributes;
    TPM2B_DIGEST authPolicy;
    TPM2B_NAME nvName;
    TPM2B_MAX_NV_BUFFER nvWriteData, nvReadData;
    UINT8 dataToWrite[] = { 0x00, 0xff, 0x55, 0xaa };
    char sharedSecret[] = "shared secret";
    int i;
    TPM2B_ENCRYPTED_SECRET encryptedSalt;
    TPMT_SYM_DEF symmetric;
    TPMA_SESSION sessionAttributes;

    // Command authorization area: one password session.
    TPMS_AUTH_COMMAND nvCmdAuth = { TPM_RS_PW, };
    TPMS_AUTH_COMMAND *nvCmdAuthArray[1] = { &nvCmdAuth };
    TSS2_SYS_CMD_AUTHS nvCmdAuths = { 1, &nvCmdAuthArray[0] };

    // Response authorization area.
    TPMS_AUTH_RESPONSE nvRspAuth;
    TPMS_AUTH_RESPONSE *nvRspAuthArray[1] = { &nvRspAuth };
    TSS2_SYS_RSP_AUTHS nvRspAuths = { 1, &nvRspAuthArray[0] };
    TPM2B_NONCE nonceCaller;

    nonceCaller.t.size = 0;

    DebugPrintf( NO_PREFIX, "\nSIMPLE HMAC SESSION TEST:\n" );

    //
    // Create NV index.
    //

    // Setup the NV index's authorization value.
    nvAuth.t.size = strlen( sharedSecret );
    for( i = 0; i < nvAuth.t.size; i++ )
        nvAuth.t.buffer[i] = sharedSecret[i];

    // Set NV index's authorization policy
    // to zero sized policy since we won't be
    // using policy to authorize.
    authPolicy.t.size = 0;

    // Now set the NV index's attributes:
    // policyRead, authWrite, and platormCreate.
    *(UINT32 *)( (void *)&nvAttributes ) = 0;
    nvAttributes.TPMA_NV_AUTHREAD = 1;
    nvAttributes.TPMA_NV_AUTHWRITE = 1;
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    // Create the NV index.
    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW,
            &nvAuth, &authPolicy, TPM20_INDEX_PASSWORD_TEST,
            TPM_ALG_SHA256, nvAttributes, 32  );
    CheckPassed( rval );

    // Add index and associated authorization value to
    // entity table.  This helps when we need
    // to calculate HMACs.
    AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );
    CheckPassed( rval );

    // Get the name of the NV index.
    rval = (*HandleToNameFunctionPtr)( TPM20_INDEX_PASSWORD_TEST,
            &nvName );
    CheckPassed( rval );

    //
    // Start HMAC authorization session:  it's an
    // unbound and unsalted session, no symmetric
    // encryption algorithm, and SHA256 is the session's
    // hash algorithm.
    //

    // Zero sized encrypted salt, since the session
    // is unsalted.
    encryptedSalt.t.size = 0;

    // No symmetric algorithm.
    symmetric.algorithm = TPM_ALG_NULL;

    // Create the session.
    // Session state (session handle, nonces, etc.) gets
    // saved into nvSession structure for later use.
    rval = StartAuthSessionWithParams( &nvSession, TPM_RH_NULL,
            0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );

    // Get the name of the session and save it in
    // the nvSession structure.
    rval = (*HandleToNameFunctionPtr)( nvSession->sessionHandle,
            &nvSession->name );
    CheckPassed( rval );

    // Initialize NV write data.
    nvWriteData.t.size = sizeof( dataToWrite );
    for( i = 0; i < nvWriteData.t.size; i++ )
    {
        nvWriteData.t.buffer[i] = dataToWrite[i];
    }

    //
    // Now setup for writing the NV index.
    //

    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Write_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
    CheckPassed( rval );

    // Configure command authorization area, except for HMAC.
    nvCmdAuths.cmdAuths[0]->sessionHandle = nvSession->sessionHandle;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 1;
    nvCmdAuths.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
    *( (UINT8 *)(&sessionAttributes ) ) = 0;
    nvCmdAuths.cmdAuths[0]->sessionAttributes = sessionAttributes;
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 1;

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // Finally!!  Write the data to the NV index.
    // If the command is successful, the command
    // HMAC was correct.
    sessionCmdRval = Tss2_Sys_NV_Write( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, &nvWriteData, 0, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( sysContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Read_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, sizeof( dataToWrite ), 0 );
    CheckPassed( rval );

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // End the session after next command.
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 0;

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // And now read the data back.
    // If the command is successful, the command
    // HMAC was correct.
    INIT_SIMPLE_TPM2B_SIZE( nvReadData );
    sessionCmdRval = Tss2_Sys_NV_Read( sysContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, sizeof( dataToWrite ), 0,
            &nvReadData, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( sysContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    // Check that write and read data are equal.
    if( memcmp( (void *)&nvReadData.t.buffer[0],
            (void *)&nvWriteData.t.buffer[0], nvReadData.t.size ) )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! read data not equal to written data\n" );
        Cleanup();
    }

    //
    // Now cleanup:  undefine the NV index and delete
    // the NV index's entity table entry.
    //

    // Setup authorization for undefining the NV index.
    nvCmdAuths.cmdAuths[0]->sessionHandle = TPM_RS_PW;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 0;
    nvCmdAuths.cmdAuths[0]->hmac.t.size = 0;

    // Undefine the NV index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext,
            TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, 0 );
    CheckPassed( rval );

    // Delete the NV index's entry in the entity table.
    rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );
    CheckPassed( rval );

    rval = EndAuthSession( nvSession );

    CheckPassed( rval );

    PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
}


void SimpleHmacOrPolicyTest( bool hmacTest )
{
    UINT32 rval, sessionCmdRval;
    TPM2B_AUTH  nvAuth;
    SESSION *nvSession, *trialPolicySession;
    TPMA_NV nvAttributes;
    TPM2B_DIGEST authPolicy;
    TPM2B_NAME nvName;
    TPM2B_MAX_NV_BUFFER nvWriteData, nvReadData;
    UINT8 dataToWrite[] = { 0x00, 0xff, 0x55, 0xaa };
    char sharedSecret[] = "shared secret";
    int i;
    TPM2B_ENCRYPTED_SECRET encryptedSalt;
    TPMT_SYM_DEF symmetric;
    TPMA_SESSION sessionAttributes;
    TPM_SE tpmSe;
    char *testString;
    char testStringHmac[] = "HMAC";
    char testStringPolicy[] = "POLICY";

    // Command authorization area: one password session.
    TPMS_AUTH_COMMAND nvCmdAuth = { TPM_RS_PW, };
    TPMS_AUTH_COMMAND *nvCmdAuthArray[1] = { &nvCmdAuth };
    TSS2_SYS_CMD_AUTHS nvCmdAuths = { 1, &nvCmdAuthArray[0] };

    // Response authorization area.
    TPMS_AUTH_RESPONSE nvRspAuth;
    TPMS_AUTH_RESPONSE *nvRspAuthArray[1] = { &nvRspAuth };
    TSS2_SYS_RSP_AUTHS nvRspAuths = { 1, &nvRspAuthArray[0] };

    TSS2_SYS_CONTEXT *simpleTestContext;
    TPM2B_NONCE nonceCaller;

    nonceCaller.t.size = 0;

    if( hmacTest )
        testString = testStringHmac;
    else
        testString = testStringPolicy;

    DebugPrintf( NO_PREFIX, "\nSIMPLE %s SESSION TEST:\n", testString );

    // Create sysContext structure.
    simpleTestContext = InitSysContext( 1000, resMgrTctiContext, &abiVersion );
    if( simpleTestContext == 0 )
    {
        InitSysContextFailure();
    }

    // Setup the NV index's authorization value.
    nvAuth.t.size = strlen( sharedSecret );
    for( i = 0; i < nvAuth.t.size; i++ )
        nvAuth.t.buffer[i] = sharedSecret[i];

    //
    // Create NV index.
    //
    if( hmacTest )
    {
        // Setup the NV index's authorization value.
        nvAuth.t.size = strlen( sharedSecret );
        for( i = 0; i < nvAuth.t.size; i++ )
            nvAuth.t.buffer[i] = sharedSecret[i];

        // Set NV index's authorization policy
        // to zero sized policy since we won't be
        // using policy to authorize.

        authPolicy.t.size = 0;
    }
    else
    {
        // Zero sized encrypted salt, since the session
        // is unsalted.

        encryptedSalt.t.size = 0;

        // No symmetric algorithm.
        symmetric.algorithm = TPM_ALG_NULL;

        //
        // Create the NV index's authorization policy
        // using a trial policy session.
        //
        rval = StartAuthSessionWithParams( &trialPolicySession,
                TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt,
                TPM_SE_TRIAL,
                &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
        CheckPassed( rval );

        rval = Tss2_Sys_PolicyAuthValue( simpleTestContext,
                trialPolicySession->sessionHandle, 0, 0 );
        CheckPassed( rval );

        // Get policy digest.
        INIT_SIMPLE_TPM2B_SIZE( authPolicy );
        rval = Tss2_Sys_PolicyGetDigest( simpleTestContext,
                trialPolicySession->sessionHandle,
                0, &authPolicy, 0 );
        CheckPassed( rval );

        // End the trial session by flushing it.
        rval = Tss2_Sys_FlushContext( simpleTestContext,
                trialPolicySession->sessionHandle );
        CheckPassed( rval );

        // And remove the trial policy session from
        // sessions table.
        rval = EndAuthSession( trialPolicySession );
        CheckPassed( rval );
    }

    // Now set the NV index's attributes:
    // policyRead, authWrite, and platormCreate.
    *(UINT32 *)( &nvAttributes ) = 0;
    if( hmacTest )
    {
        nvAttributes.TPMA_NV_AUTHREAD = 1;
        nvAttributes.TPMA_NV_AUTHWRITE = 1;
    }
    else
    {
        nvAttributes.TPMA_NV_POLICYREAD = 1;
        nvAttributes.TPMA_NV_POLICYWRITE = 1;
    }
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    // Create the NV index.
    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW,
            &nvAuth, &authPolicy, TPM20_INDEX_PASSWORD_TEST,
            TPM_ALG_SHA256, nvAttributes, 32  );
    CheckPassed( rval );

    // Add index and associated authorization value to
    // entity table.  This helps when we need
    // to calculate HMACs.
    AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );
    CheckPassed( rval );

    // Get the name of the NV index.
    rval = (*HandleToNameFunctionPtr)(
            TPM20_INDEX_PASSWORD_TEST,
            &nvName );
    CheckPassed( rval );


    //
    // Start HMAC or real (non-trial) policy authorization session:
    // it's an unbound and unsalted session, no symmetric
    // encryption algorithm, and SHA256 is the session's
    // hash algorithm.
    //

    // Zero sized encrypted salt, since the session
    // is unsalted.
    encryptedSalt.t.size = 0;

    // No symmetric algorithm.
    symmetric.algorithm = TPM_ALG_NULL;

    // Create the session, hmac or policy depending
    // on hmacTest.
    // Session state (session handle, nonces, etc.) gets
    // saved into nvSession structure for later use.
    if( hmacTest )
        tpmSe = TPM_SE_HMAC;
    else
        tpmSe = TPM_SE_POLICY;

    rval = StartAuthSessionWithParams( &nvSession, TPM_RH_NULL,
            0, TPM_RH_NULL, 0, &nonceCaller, &encryptedSalt, tpmSe,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );

    // Get the name of the session and save it in
    // the nvSession structure.
    rval = (*HandleToNameFunctionPtr)( nvSession->sessionHandle,
            &(nvSession->name) );
    CheckPassed( rval );

    // Initialize NV write data.
    nvWriteData.t.size = sizeof( dataToWrite );
    for( i = 0; i < nvWriteData.t.size; i++ )
    {
        nvWriteData.t.buffer[i] = dataToWrite[i];
    }

    //
    // Now setup for writing the NV index.
    //
    if( !hmacTest )
    {
        // Send policy command.
        rval = Tss2_Sys_PolicyAuthValue( simpleTestContext,
                nvSession->sessionHandle, 0, 0 );
        CheckPassed( rval );
    }

    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Write_Prepare( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
    CheckPassed( rval );

    // Configure command authorization area, except for HMAC.
    nvCmdAuths.cmdAuths[0]->sessionHandle =
            nvSession->sessionHandle;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 1;
    nvCmdAuths.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
    *( (UINT8 *)(&sessionAttributes ) ) = 0;
    nvCmdAuths.cmdAuths[0]->sessionAttributes = sessionAttributes;
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 1;

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // Finally!!  Write the data to the NV index.
    // If the command is successful, the command
    // HMAC was correct.
    sessionCmdRval = Tss2_Sys_NV_Write( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, &nvWriteData, 0, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( simpleTestContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    if( !hmacTest )
    {
        // Send policy command.
        rval = Tss2_Sys_PolicyAuthValue( simpleTestContext,
                nvSession->sessionHandle, 0, 0 );
        CheckPassed( rval );
    }
    // First call prepare in order to create cpBuffer.
    rval = Tss2_Sys_NV_Read_Prepare( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            sizeof( dataToWrite ), 0 );
    CheckPassed( rval );

    // Roll nonces for command
    RollNonces( nvSession, &nvCmdAuths.cmdAuths[0]->nonce );

    // End the session after next command.
    nvCmdAuths.cmdAuths[0]->sessionAttributes.continueSession = 0;

    // Complete command authorization area, by computing
    // HMAC and setting it in nvCmdAuths.
    rval = ComputeCommandHmacs( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths,
            TPM_RC_FAILURE );
    CheckPassed( rval );

    // And now read the data back.
    // If the command is successful, the command
    // HMAC was correct.
    INIT_SIMPLE_TPM2B_SIZE( nvReadData );
    sessionCmdRval = Tss2_Sys_NV_Read( simpleTestContext,
            TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, sizeof( dataToWrite ), 0,
            &nvReadData, &nvRspAuths );
    CheckPassed( sessionCmdRval );

    // Roll nonces for response
    RollNonces( nvSession, &nvRspAuths.rspAuths[0]->nonce );

    if( sessionCmdRval == TPM_RC_SUCCESS )
    {
        // If the command was successful, check the
        // response HMAC to make sure that the
        // response was received correctly.
        rval = CheckResponseHMACs( simpleTestContext, sessionCmdRval,
                &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST,
                TPM20_INDEX_PASSWORD_TEST, &nvRspAuths );
        CheckPassed( rval );
    }

    // Check that write and read data are equal.
    if( memcmp( (void *)&nvReadData.t.buffer[0],
            (void *)&nvWriteData.t.buffer[0], nvReadData.t.size ) )
    {
        DebugPrintf( NO_PREFIX, "ERROR!! read data not equal to written data\n" );
        Cleanup();
    }

    //
    // Now cleanup:  undefine the NV index and delete
    // the NV index's entity table entry.
    //

    // Setup authorization for undefining the NV index.
    nvCmdAuths.cmdAuths[0]->sessionHandle = TPM_RS_PW;
    nvCmdAuths.cmdAuths[0]->nonce.t.size = 0;
    nvCmdAuths.cmdAuths[0]->hmac.t.size = 0;

    // Undefine the NV index.
    rval = Tss2_Sys_NV_UndefineSpace( simpleTestContext,
            TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST,
            &nvCmdAuths, 0 );
    CheckPassed( rval );

    // Delete the NV index's entry in the entity table.
    rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );
    CheckPassed( rval );

    // Remove the real session from sessions table.
    rval = EndAuthSession( nvSession );

    CheckPassed( rval );

    TeardownSysContext( &simpleTestContext );

}


typedef struct {
    TPMI_DH_OBJECT tpmKey;
    TPMI_DH_ENTITY bound;
    TPM2B_MAX_BUFFER *salt;
    char hmacTestDescription[50];
} HMAC_TEST_SETUP;

TPM2B_MAX_BUFFER nullSalt = { { 0, { 0xa4 } }, };
TPM2B_MAX_BUFFER nonNullSalt = { { 2, { 0xa5, 0 } } };

HMAC_TEST_SETUP hmacTestSetups[] =
{
#ifndef SKIP_UNBOUND_UNSALTED_HMAC_TEST
    { TPM_RH_NULL, TPM_RH_NULL, &nullSalt, "UNBOUND/UNSALTED SESSION TEST" },
#endif //SKIP_UNBOUND_UNSALTED_HMAC_TEST
#ifndef SKIP_BOUND_SESSION_HMAC_TEST
    { TPM_RH_NULL, TPM20_INDEX_PASSWORD_TEST, &nullSalt, "BOUND SESSION TEST" },
#endif //SKIP_BOUND_SESSION_HMAC_TEST
#ifndef SKIP_SALTED_SESSION_HMAC_TEST
    { 0, TPM_RH_NULL, &nonNullSalt, "SALTED SESSION TEST" },
#endif //SKIP_SALTED_SESSION_HMAC_TEST
#ifndef SKIP_BOUND_SALTED_SESSION_HMAC_TEST
    { 0, TPM20_INDEX_PASSWORD_TEST, &nonNullSalt, "BOUND/SALTED SESSION TEST" },
#endif //SKIP_BOUND_SALTED_SESSION_HMAC_TEST
};

#define PLAINTEXT_SESSION 0
#define DECRYPT_SESSION 1
#define ENCRYPT_SESSION 2

//UINT8 decryptEncryptSetups[] = { PLAINTEXT_SESSION, DECRYPT_SESSION, ENCRYPT_SESSION };
UINT8 decryptEncryptSetups[] = { PLAINTEXT_SESSION };

#define CFB_MODE 0
#define XOR_MODE 1

void HmacSessionTest()
{
    UINT32 rval;
    unsigned int i, j, k, decryptEncryptMode;
    TPM2B_MAX_NV_BUFFER nvWriteData;
    UINT8 dataToWrite[] = { 0x00, 0xff, 0x55, 0xaa };
    TPM2B_NAME nvName;
    TPM_RC sessionCmdRval;

    SESSION *nvSession;
    TSS2_SYS_CONTEXT *rdSysContext;
    TSS2_SYS_CONTEXT *wrSysContext;
    TPM2B_AUTH  nvAuth;
    TPMT_SYM_DEF symmetric;
    TPM2B_NONCE nonceOlder;

    // Create two sysContext structures.
    rdSysContext = InitSysContext( 1000, resMgrTctiContext, &abiVersion );
    if( rdSysContext == 0 )
    {
        InitSysContextFailure();
    }

    wrSysContext = InitSysContext( 1000, resMgrTctiContext, &abiVersion );
    if( wrSysContext == 0 )
    {
        InitSysContextFailure();
    }

    char sharedSecret[] = "shared secret";

    char buffer1contents[] = "test";
    char buffer2contents[] = "string";

    TPM2B_MAX_BUFFER buffer1;
    TPM2B_MAX_BUFFER buffer2;

//    TPM2B_IV ivIn, ivOut;
    TPM2B_MAX_NV_BUFFER nvData;
    TPM2B_ENCRYPTED_SECRET encryptedSalt;

    encryptedSalt.t.size = 0;
//    ivIn.t.size = 0;
//    ivOut.t.size = 0;

    buffer1.t.size = strlen( buffer1contents );
    memcpy (buffer1.t.buffer, buffer1contents, buffer1.t.size );
    buffer2.t.size = strlen( buffer2contents );
    memcpy (buffer2.t.buffer, buffer2contents, buffer2.t.size );


    for( j = 0; j < sizeof( hmacTestSetups ) / sizeof( HMAC_TEST_SETUP ); j++ )
    {
        if( hmacTestSetups[j].salt == &nonNullSalt )
        {
            hmacTestSetups[j].tpmKey = handle2048rsa;
        }
    }
    DebugPrintf( NO_PREFIX, "\nHMAC SESSION TESTS:\n" );

    for( j = 0; j < sizeof( hmacTestSetups ) / sizeof( HMAC_TEST_SETUP ); j++ )
    {
        // Iterate through variations of decrypt and encrypt sessions.
        for( k = 0; k < sizeof( decryptEncryptSetups ); k++ )
        {
            for( decryptEncryptMode = CFB_MODE; decryptEncryptMode <= XOR_MODE; decryptEncryptMode++ )
            {
                TPMS_AUTH_COMMAND sessionData = { TPM_RS_PW, };
                TPMS_AUTH_RESPONSE sessionDataOut;
                TPMS_AUTH_COMMAND *sessionDataArray[1] = { &sessionData };
                TPMS_AUTH_RESPONSE *sessionDataOutArray[1] = { &sessionDataOut };
                TSS2_SYS_CMD_AUTHS sessionsData = { 1, &sessionDataArray[0] };
                TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, &sessionDataOutArray[0] };

                TPMT_RSA_DECRYPT  inScheme;
                TPM2B_DATA label;
                TPM2B_DIGEST authPolicy;
                TPMA_NV nvAttributes;

                DebugPrintf( NO_PREFIX, "\n\n%s:\n", hmacTestSetups[j].hmacTestDescription );

                if( hmacTestSetups[j].tpmKey != TPM_RH_NULL )
                {
                    sessionsData.cmdAuths[0]->hmac = loadedSha1KeyAuth;
                    sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;
                    sessionsData.cmdAuths[0]->nonce.t.size = 0;
                    *( (UINT8 *)(&sessionData.sessionAttributes ) ) = 0;

                    inScheme.scheme = TPM_ALG_OAEP;
                    inScheme.details.oaep.hashAlg = TPM_ALG_SHA1;
                    memcpy( &( label.b.buffer ), "SECRET", 1 + strlen( "SECRET" ) );
                    label.t.size = strlen( "SECRET" ) + 1;

                    // Encrypt salt with tpmKey.
                    INIT_SIMPLE_TPM2B_SIZE( encryptedSalt );
                    rval = Tss2_Sys_RSA_Encrypt( sysContext, handle2048rsa,
                            0, (TPM2B_PUBLIC_KEY_RSA *)( hmacTestSetups[j].salt ),
                            &inScheme, &label, (TPM2B_PUBLIC_KEY_RSA *)&encryptedSalt, 0 );
                    CheckPassed( rval );
                }

                // init hmac
                sessionData.hmac.t.size = 0;

                // NOW CREATE THE INDEX
                authPolicy.t.size = 0;

                nvAuth.t.size = strlen( sharedSecret );
                for( i = 0; i < nvAuth.t.size; i++ )
                    nvAuth.t.buffer[i] = sharedSecret[i];

                // Now set the attributes.
                *(UINT32 *)( &nvAttributes ) = 0;
                nvAttributes.TPMA_NV_AUTHREAD = 1;
                nvAttributes.TPMA_NV_AUTHWRITE = 1;
                nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

                sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;
                sessionsData.cmdAuths[0]->nonce.t.size = 0;
                sessionsData.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
                sessionData.hmac.t.size = 0;

                // Undefine the index in case a previous test failure left it defined.
                rval = Tss2_Sys_NV_UndefineSpace( wrSysContext, TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST, &sessionsData, 0 );

                rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW, &nvAuth, &authPolicy,
                        TPM20_INDEX_PASSWORD_TEST, TPM_ALG_SHA1, nvAttributes, 32  );
                CheckPassed( rval );

                AddEntity( TPM20_INDEX_PASSWORD_TEST, &nvAuth );
                CheckPassed( rval );

                // Get the name using TPM function.
                rval = (*HandleToNameFunctionPtr)( TPM20_INDEX_PASSWORD_TEST, &nvName );
                CheckPassed( rval );

                //
                // Start session
                //
                nonceOlder.t.size = GetDigestSize( TPM_ALG_SHA1 );
                for( i = 0; i < nonceOlder.t.size; i++ )
                    nonceOlder.t.buffer[i] = 0;

                if( decryptEncryptSetups[k] == PLAINTEXT_SESSION )
                {
                    symmetric.algorithm = TPM_ALG_NULL;
                }
                else if( decryptEncryptSetups[k] == DECRYPT_SESSION || decryptEncryptSetups[k] == ENCRYPT_SESSION )
                {
                    if( decryptEncryptMode == CFB_MODE )
                    {
                        symmetric.algorithm = TPM_ALG_AES;
                        symmetric.keyBits.aes = 128;
                        symmetric.mode.aes = TPM_ALG_CFB;
                    }
                    else if( decryptEncryptMode == XOR_MODE )
                    {
                        symmetric.algorithm = TPM_ALG_XOR;
                        symmetric.keyBits.exclusiveOr = TPM_ALG_SHA256;
                    }
                }

                rval = StartAuthSessionWithParams( &nvSession, hmacTestSetups[j].tpmKey,
                        hmacTestSetups[j].salt, hmacTestSetups[j].bound, &nvAuth, &nonceOlder, &encryptedSalt,
                        TPM_SE_HMAC, &symmetric, TPM_ALG_SHA1, resMgrTctiContext );
                CheckPassed( rval );

                // Get and print name of the session.
                rval = (*HandleToNameFunctionPtr)( nvSession->sessionHandle, &nvSession->name );
                CheckPassed( rval );

                DebugPrintf( NO_PREFIX, "Name of authSession: " );
                PrintSizedBuffer( (TPM2B *)&nvSession->name );

                // Init write data.
                nvWriteData.t.size = sizeof( dataToWrite );

                for( i = 0; i < nvWriteData.t.size; i++ )
                {
                    nvWriteData.t.buffer[i] = dataToWrite[i];
                }

                if( decryptEncryptSetups[k] == DECRYPT_SESSION )
                {
                    if( decryptEncryptMode == CFB_MODE )
                    {
//                        rval = EncryptCFB( &nvSession, &( nvWriteData.b ) );
                    }
                    else if( decryptEncryptMode == XOR_MODE )
                    {
//                        rval = EncryptXOR( &nvSession, &( nvWriteData.b ) );
                    }
                    sessionsData.cmdAuths[0]->sessionAttributes.decrypt = 1;
                }
                else
                {
                    sessionsData.cmdAuths[0]->sessionAttributes.decrypt = 0;
                }
                sessionsData.cmdAuths[0]->sessionAttributes.encrypt = 0;

                CheckPassed( rval );

                sessionsData.cmdAuths[0]->sessionHandle = nvSession->sessionHandle;
                sessionsData.cmdAuths[0]->nonce.t.size = 1;
                sessionsData.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;

                // Roll nonces for command
                RollNonces( nvSession, &sessionsData.cmdAuths[0]->nonce );

                // Now try writing with bad HMAC.
                rval = Tss2_Sys_NV_Write_Prepare( wrSysContext, TPM20_INDEX_PASSWORD_TEST,
                        TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
                CheckPassed( rval );

                rval = ComputeCommandHmacs( wrSysContext,
                        TPM20_INDEX_PASSWORD_TEST,
                        TPM20_INDEX_PASSWORD_TEST, &sessionsData, TPM_RC_FAILURE );
                CheckPassed( rval );

                // Diddle with HMAC to force failure
                sessionsData.cmdAuths[0]->hmac.t.buffer[0] =
                        ~( sessionsData.cmdAuths[0]->hmac.t.buffer[0] );

                sessionCmdRval = Tss2_Sys_NV_Write( wrSysContext, TPM20_INDEX_PASSWORD_TEST,
                        TPM20_INDEX_PASSWORD_TEST,
                        &sessionsData, &nvWriteData, 0, &sessionsDataOut );
                CheckFailed( sessionCmdRval, TPM_RC_S + TPM_RC_1 + TPM_RC_AUTH_FAIL );

                // Since command failed, no need to roll nonces.

                TestDictionaryAttackLockReset();

                // Now try writing with good HMAC.

                // Do stage 1 of NVRead, followed by stage 1 and 2 of NVWrite, followed by
                // stage 2 of NVRead.  This tests that the staged processing is thread-safe.
                sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 0;
                rval = Tss2_Sys_NV_Read_Prepare( rdSysContext, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, sizeof( dataToWrite ), 0 );
                CheckPassed( rval );

                sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 1;
                rval = Tss2_Sys_NV_Write_Prepare( wrSysContext, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST,
                        &nvWriteData, 0 );
                CheckPassed( rval );

                rval = ComputeCommandHmacs( wrSysContext, TPM20_INDEX_PASSWORD_TEST,
                        TPM20_INDEX_PASSWORD_TEST, &sessionsData, sessionCmdRval );
                CheckPassed( rval );

                sessionCmdRval = Tss2_Sys_NV_Write( wrSysContext,
                        TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsData, &nvWriteData, 0, &sessionsDataOut );
                CheckPassed( sessionCmdRval );
                if( sessionCmdRval == TPM_RC_SUCCESS )
                {
                    // Roll nonces for response
                    RollNonces( nvSession, &sessionsDataOut.rspAuths[0]->nonce );

                    rval = CheckResponseHMACs( wrSysContext, sessionCmdRval,
                            &sessionsData, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsDataOut );
                    CheckPassed( rval );
                }

                // Roll nonces for command
                RollNonces( nvSession, &sessionsData.cmdAuths[0]->nonce );

                sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 0;
                rval = ComputeCommandHmacs( rdSysContext, TPM20_INDEX_PASSWORD_TEST,
                       TPM20_INDEX_PASSWORD_TEST, &sessionsData, sessionCmdRval );
                CheckPassed( rval );

                if( decryptEncryptSetups[k] == ENCRYPT_SESSION )
                {
                    sessionsData.cmdAuths[0]->sessionAttributes.encrypt = 1;
                }
                else
                {
                    sessionsData.cmdAuths[0]->sessionAttributes.encrypt = 0;
                }
                sessionsData.cmdAuths[0]->sessionAttributes.decrypt = 0;

                INIT_SIMPLE_TPM2B_SIZE( nvData );
                sessionCmdRval = Tss2_Sys_NV_Read( rdSysContext, TPM20_INDEX_PASSWORD_TEST,
                        TPM20_INDEX_PASSWORD_TEST, &sessionsData, sizeof( dataToWrite ), 0, &nvData, &sessionsDataOut );
                CheckPassed( sessionCmdRval );
                if( sessionCmdRval == TPM_RC_SUCCESS )
                {
                    // Roll nonces for response
                    RollNonces( nvSession, &sessionsDataOut.rspAuths[0]->nonce );

                    rval = CheckResponseHMACs( rdSysContext, sessionCmdRval,
                            &sessionsData, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsDataOut );
                    CheckPassed( rval );

                    if( decryptEncryptSetups[k] == ENCRYPT_SESSION )
                    {
                        if( decryptEncryptMode == CFB_MODE )
                        {
//                            rval = EncryptCFB( nvSession, &( nvData.b ) );
                        }
                        else if( decryptEncryptMode == XOR_MODE )
                        {
//                            rval = EncryptXOR( nvSession, &( nvData.b ) );
                        }
                        CheckPassed( rval );
                    }

                    // Check that write actually worked.
                    rval = CompareTPM2B( &(nvWriteData.b), &(nvData.b) );
                    CheckPassed( rval );
                }

                //
                // NOTE:  When running against version of the simulator for TPM spec versions later
                // than version 0.98, in order for the session to act as a bound session when accessing
                // the bind entity, we will need to restart the session here since the name of the bound
                // entity changed.
                //
                if( hmacTestSetups[j].bound != TPM_RH_NULL )
                {
                    rval = EndAuthSession( nvSession );
                    CheckPassed( rval );

                    //
                    // Start session
                    //
                    nonceOlder.t.size = GetDigestSize( TPM_ALG_SHA1 );
                    for( i = 0; i < nonceOlder.t.size; i++ )
                        nonceOlder.t.buffer[i] = 0;

                    symmetric.algorithm = TPM_ALG_AES;
                    symmetric.keyBits.aes = 128;
                    symmetric.mode.aes = TPM_ALG_CFB;

                    EndAuthSession (nvSession);
                    rval = StartAuthSessionWithParams( &nvSession, hmacTestSetups[j].tpmKey,  hmacTestSetups[j].salt, hmacTestSetups[j].bound, &nvAuth, &nonceOlder, &encryptedSalt, TPM_SE_HMAC, &symmetric, TPM_ALG_SHA1, resMgrTctiContext );
                    CheckPassed( rval );

                    CopySizedByteBuffer( &( nvSession->authValueBind.b ), &( nvAuth.b ) );

                    // Now try writing with good HMAC.
                    sessionsData.cmdAuths[0]->sessionHandle = nvSession->sessionHandle;
                    sessionsData.cmdAuths[0]->nonce.t.size = 1;
                    sessionsData.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
                    sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 1;
                    sessionsData.cmdAuths[0]->sessionAttributes.decrypt = 1;

                    // TBD:  Need to encrypt data before sending.

                    rval = Tss2_Sys_NV_Write_Prepare( wrSysContext, TPM20_INDEX_PASSWORD_TEST,
                            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
                    CheckPassed( rval );

                    // Roll nonces for command
                    RollNonces( nvSession, &sessionsData.cmdAuths[0]->nonce );

                    rval = ComputeCommandHmacs( wrSysContext, TPM20_INDEX_PASSWORD_TEST,
                            TPM20_INDEX_PASSWORD_TEST, &sessionsData, TPM_RC_FAILURE );
                    CheckPassed( rval );

                    sessionCmdRval = Tss2_Sys_NV_Write( wrSysContext, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsData, &nvWriteData, 0, &sessionsDataOut );
                    sessionsData.cmdAuths[0]->sessionAttributes.decrypt = 0;
                    CheckPassed( sessionCmdRval );
                    if( sessionCmdRval == TPM_RC_SUCCESS )
                    {
                        // Roll nonces for response
                        RollNonces( nvSession, &sessionsDataOut.rspAuths[0]->nonce );

                        rval = CheckResponseHMACs( wrSysContext, sessionCmdRval,
                                &sessionsData, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsDataOut );
                        CheckPassed( rval );
                    }

                    // Need to do GetSessionAuditDigest to check that audit digest changed.

                    sessionsData.cmdAuths[0]->sessionAttributes.continueSession = 0;
                    sessionsData.cmdAuths[0]->sessionAttributes.encrypt = 1;
                    sessionsData.cmdAuths[0]->sessionAttributes.audit = 1;

                    rval = Tss2_Sys_NV_Read_Prepare( rdSysContext, TPM20_INDEX_PASSWORD_TEST,
                            TPM20_INDEX_PASSWORD_TEST, sizeof( dataToWrite ), 0 );
                    CheckPassed( rval );

                    // Roll nonces for command
                    RollNonces( nvSession, &sessionsData.cmdAuths[0]->nonce );

                    rval = ComputeCommandHmacs( rdSysContext, TPM20_INDEX_PASSWORD_TEST,
                            TPM20_INDEX_PASSWORD_TEST, &sessionsData, sessionCmdRval );
                    CheckPassed( rval );

                    INIT_SIMPLE_TPM2B_SIZE( nvData );
                    sessionCmdRval = Tss2_Sys_NV_Read( rdSysContext, TPM20_INDEX_PASSWORD_TEST,
                            TPM20_INDEX_PASSWORD_TEST, &sessionsData, sizeof( dataToWrite ), 0, &nvData, &sessionsDataOut );
                    sessionsData.cmdAuths[0]->sessionAttributes.encrypt = 0;
                    sessionsData.cmdAuths[0]->sessionAttributes.audit = 0;
                    if( sessionCmdRval == TPM_RC_SUCCESS )
                    {
                        // Roll nonces for response
                        RollNonces( nvSession, &sessionsDataOut.rspAuths[0]->nonce );

                        rval = CheckResponseHMACs( rdSysContext, sessionCmdRval,
                                &sessionsData, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &sessionsDataOut );
                        CheckPassed( rval );
                    }

                    // TBD:  Need to decrypt response data.

                    CheckPassed( rval );
                    // TBD:  Need to do GetSessionAuditDigest to check that audit digest changed.
                }

                // Removed comparison for now until we figure out how to properly
                // encrypt data before writing to NV index.
                //        rval = CompareTPM2B( &(nvWriteData.b), &(nvData.b) );
                //        CheckPassed( rval );

                sessionsData.cmdAuths[0]->sessionHandle = TPM_RS_PW;
                sessionsData.cmdAuths[0]->nonce.t.size = 0;
                sessionsData.cmdAuths[0]->nonce.t.buffer[0] = 0xa5;
                sessionData.hmac.t.size = 0;
                // Now undefine the index.
                rval = Tss2_Sys_NV_UndefineSpace( wrSysContext, TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST, &sessionsData, 0 );
                CheckPassed( rval );
                rval = DeleteEntity( TPM20_INDEX_PASSWORD_TEST );
                CheckPassed( rval );
                rval = EndAuthSession( nvSession );
                CheckPassed( rval );
            }
        }
    }

    TeardownSysContext( &wrSysContext );
    TeardownSysContext( &rdSysContext );

}

UINT32 writeDataString = 0xdeadbeef;

void TestEncryptDecryptSession()
{
    TSS2_RC             rval = TSS2_RC_SUCCESS;
    SESSION             *encryptDecryptSession;
    TPMT_SYM_DEF        symmetric;
    TPM2B_MAX_NV_BUFFER writeData, encryptedWriteData;
    TPM2B_MAX_NV_BUFFER encryptedReadData, decryptedReadData,
                        readData;
    size_t              decryptParamSize;
    uint8_t             *decryptParamBuffer;
    size_t              encryptParamSize;
    uint8_t             *encryptParamBuffer;
    TPM2B_AUTH          nvAuth;
    TPM2B_DIGEST        authPolicy;
    TPMA_NV             nvAttributes;
    int                 i;
    TPMA_SESSION        sessionAttributes;
    TPM2B_NONCE         nonceCaller;

    nonceCaller.t.size = 0;

    // Authorization structure for undefine command.
    TPMS_AUTH_COMMAND nvUndefineAuth;

    // Create and init authorization area for undefine command:
    // only 1 authorization area.
    TPMS_AUTH_COMMAND *nvUndefineAuthArray[1] = { &nvUndefineAuth };

    // Authorization array for command (only has one auth structure).
    TSS2_SYS_CMD_AUTHS nvUndefineAuths = { 1, &nvUndefineAuthArray[0] };

    DebugPrintf( NO_PREFIX, "\n\nDECRYPT/ENCRYPT SESSION TESTS:\n" );

    writeData.t.size = sizeof( writeDataString );
    memcpy( (void *)&writeData.t.buffer, (void *)&writeDataString,
            sizeof( writeDataString ) );


    // Create NV index with empty auth value.
    *(UINT32 *)( (void *)&nvAttributes ) = 0;
    nvAttributes.TPMA_NV_AUTHREAD = 1;
    nvAttributes.TPMA_NV_AUTHWRITE = 1;
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    // No authorization required.
    authPolicy.t.size = 0;
    nvAuth.t.size = 0;
    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW,
            &nvAuth, &authPolicy, TPM20_INDEX_TEST1,
            TPM_ALG_SHA1, nvAttributes,
            sizeof( writeDataString ) );

    //
    // 1st pass with CFB mode.
    // 2nd pass with XOR mode.
    //
    for( i = 0; i < 2; i++ )
    {
        // Authorization structure for NV
        // read/write commands.
        TPMS_AUTH_COMMAND nvRdWrCmdAuth;

        // Authorization structure for
        // encrypt/decrypt session.
        TPMS_AUTH_COMMAND decryptEncryptSessionCmdAuth;

        // Create and init authorization area for
        // NV read/write commands:
        // 2 authorization areas.
        TPMS_AUTH_COMMAND *nvRdWrCmdAuthArray[2] =
                { &nvRdWrCmdAuth, &decryptEncryptSessionCmdAuth };

        // Authorization array for commands
        // (has two auth structures).
        TSS2_SYS_CMD_AUTHS nvRdWrCmdAuths =
                { 2, &nvRdWrCmdAuthArray[0] };

        // Authorization structure for NV read/write responses.
        TPMS_AUTH_RESPONSE nvRdWrRspAuth;
        // Authorization structure for decrypt/encrypt
        // session responses.
        TPMS_AUTH_RESPONSE decryptEncryptSessionRspAuth;

        // Create and init authorization area for NV
        // read/write responses:  2 authorization areas.
        TPMS_AUTH_RESPONSE *nvRdWrRspAuthArray[2] =
                { &nvRdWrRspAuth, &decryptEncryptSessionRspAuth };
        // Authorization array for responses
        // (has two auth structures).
        TSS2_SYS_RSP_AUTHS nvRdWrRspAuths =
                { 2, &nvRdWrRspAuthArray[0] };

        // Setup session parameters.
        if( i == 0 )
        {
            // AES encryption/decryption and CFB mode.
            symmetric.algorithm = TPM_ALG_AES;
            symmetric.keyBits.aes = 128;
            symmetric.mode.aes = TPM_ALG_CFB;
        }
        else
        {
            // XOR encryption/decryption.
            symmetric.algorithm = TPM_ALG_XOR;
            symmetric.keyBits.exclusiveOr = TPM_ALG_SHA256;
        }

        // Start policy session for decrypt/encrypt session.
        rval = StartAuthSessionWithParams( &encryptDecryptSession,
                TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, 0, TPM_SE_POLICY,
                &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
        CheckPassed( rval );

        //
        // Write TPM index with encrypted parameter used
        // as the data to write.  Set session for encrypt.
        // Use asyncronous APIs to do this.
        //
        // 1st time:  use null buffer, 2nd time use populated one;
        // this tests different cases for SetDecryptParam function.
        //

        // Prepare the input parameters, using unencypted
        // write data.  This will be encrypted before the
        // command is sent to the TPM.
        rval = Tss2_Sys_NV_Write_Prepare( sysContext,
                TPM20_INDEX_TEST1, TPM20_INDEX_TEST1,
                ( i == 0 ? (TPM2B_MAX_NV_BUFFER *)0 : &writeData ),
                0 );
        CheckPassed( rval );

        // Set up password authorization session structure.
        nvRdWrCmdAuth.sessionHandle = TPM_RS_PW;
        nvRdWrCmdAuth.nonce.t.size = 0;
        *( (UINT8 *)((void *)&nvRdWrCmdAuth.sessionAttributes ) ) = 0;
        nvRdWrCmdAuth.hmac.t.size = nvAuth.t.size;
        memcpy( (void *)&nvRdWrCmdAuth.hmac.t.buffer[0],
                (void *)&nvAuth.t.buffer[0],
                nvRdWrCmdAuth.hmac.t.size );

        // Set up encrypt/decrypt session structure.
        decryptEncryptSessionCmdAuth.sessionHandle =
                encryptDecryptSession->sessionHandle;
        decryptEncryptSessionCmdAuth.nonce.t.size = 0;
        *( (UINT8 *)((void *)&sessionAttributes ) ) = 0;
        decryptEncryptSessionCmdAuth.sessionAttributes =
                sessionAttributes;
        decryptEncryptSessionCmdAuth.sessionAttributes.continueSession
                = 1;
        decryptEncryptSessionCmdAuth.sessionAttributes.decrypt = 1;
        decryptEncryptSessionCmdAuth.hmac.t.size = 0;

        rval = Tss2_Sys_SetCmdAuths( sysContext, &nvRdWrCmdAuths );
        CheckPassed( rval );

        // Get decrypt parameter.
        rval = Tss2_Sys_GetDecryptParam( sysContext,
                &decryptParamSize,
                (const uint8_t **)&decryptParamBuffer );
        CheckPassed( rval );

        if( i == 0 )
        {
            // 1st pass:  test case of Prepare inputting a NULL decrypt
            // param; decryptParamSize should be 0.
            if( decryptParamSize != 0 )
            {
                DebugPrintf( NO_PREFIX, "ERROR!! decryptParamSize != 0\n" );
                Cleanup();
            }
        }

        // Roll nonces for command.
        RollNonces( encryptDecryptSession,
                &decryptEncryptSessionCmdAuth.nonce );

        // Encrypt write data.
        rval = EncryptCommandParam( encryptDecryptSession,
                (TPM2B_MAX_BUFFER *)&encryptedWriteData,
                (TPM2B_MAX_BUFFER *)&writeData, &nvAuth );
        CheckPassed( rval );

        // Now set decrypt parameter.
        rval = Tss2_Sys_SetDecryptParam( sysContext,
                (uint8_t )encryptedWriteData.t.size,
                (uint8_t *)&encryptedWriteData.t.buffer[0] );
        CheckPassed( rval );

        // Now write the data to the NV index.
        rval = Tss2_Sys_ExecuteAsync( sysContext );
        CheckPassed( rval );

        rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
        CheckPassed( rval );

        rval = Tss2_Sys_GetRspAuths( sysContext, &nvRdWrRspAuths );
        CheckPassed( rval );

        // Roll the nonces for response
        RollNonces( encryptDecryptSession,
                &nvRdWrRspAuths.rspAuths[1]->nonce );


        // Don't need nonces for anything else, so roll
        // the nonces for next command.
        RollNonces( encryptDecryptSession,
                &decryptEncryptSessionCmdAuth.nonce );

        // Now read the data without encrypt set.
        nvRdWrCmdAuths.cmdAuthsCount = 1;
        nvRdWrRspAuths.rspAuthsCount = 1;
        INIT_SIMPLE_TPM2B_SIZE( readData );
        rval = Tss2_Sys_NV_Read( sysContext, TPM20_INDEX_TEST1,
                TPM20_INDEX_TEST1, &nvRdWrCmdAuths,
                sizeof( writeDataString ), 0, &readData,
                &nvRdWrRspAuths );
        CheckPassed( rval );
        nvRdWrCmdAuths.cmdAuthsCount = 2;
        nvRdWrRspAuths.rspAuthsCount = 2;

        // Roll the nonces for response
        RollNonces( encryptDecryptSession,
                &nvRdWrRspAuths.rspAuths[1]->nonce );

        // Check that write and read data are equal.  This
        // verifies that the decrypt session was setup correctly.
        // If it wasn't, the data stored in the TPM would still
        // be encrypted, and this test would fail.
        if( memcmp( (void *)&readData.t.buffer[0],
                (void *)&writeData.t.buffer[0], readData.t.size ) )
        {
            DebugPrintf( NO_PREFIX, "ERROR!! read data not equal to written data\n" );
            Cleanup();
        }

        //
        // Read TPM index with encrypt session; use
        // syncronous APIs to do this.
        //

        rval = Tss2_Sys_NV_Read_Prepare( sysContext, TPM20_INDEX_TEST1,
                TPM20_INDEX_TEST1, sizeof( writeDataString ), 0 );
        CheckPassed( rval );

        // Roll the nonces for next command.
        RollNonces( encryptDecryptSession,
                &decryptEncryptSessionCmdAuth.nonce );

        decryptEncryptSessionCmdAuth.sessionAttributes.decrypt = 0;
        decryptEncryptSessionCmdAuth.sessionAttributes.encrypt = 1;
        decryptEncryptSessionCmdAuth.sessionAttributes.continueSession =
                1;

        rval = Tss2_Sys_SetCmdAuths( sysContext, &nvRdWrCmdAuths );
        CheckPassed( rval );

        //
        // Now Read the data.
        //
        rval = Tss2_Sys_Execute( sysContext );
        CheckPassed( rval );

        rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize,
                (const uint8_t **)&encryptParamBuffer );
        CheckPassed( rval );

        rval = Tss2_Sys_GetRspAuths( sysContext, &nvRdWrRspAuths );
        CheckPassed( rval );

        // Roll the nonces for response
        RollNonces( encryptDecryptSession,
                &nvRdWrRspAuths.rspAuths[1]->nonce );

        // Decrypt read data.
        encryptedReadData.t.size = encryptParamSize;
        memcpy( (void *)&encryptedReadData.t.buffer[0],
                (void *)encryptParamBuffer, encryptParamSize );
        INIT_SIMPLE_TPM2B_SIZE( decryptedReadData );
        rval = DecryptResponseParam( encryptDecryptSession,
                (TPM2B_MAX_BUFFER *)&decryptedReadData,
                (TPM2B_MAX_BUFFER *)&encryptedReadData, &nvAuth );
        CheckPassed( rval );

        // Roll the nonces.
        RollNonces( encryptDecryptSession,
                &nvRdWrRspAuths.rspAuths[1]->nonce );

        rval = Tss2_Sys_SetEncryptParam( sysContext,
                (uint8_t)decryptedReadData.t.size,
                (uint8_t *)&decryptedReadData.t.buffer[0] );
        CheckPassed( rval );

        // Get the command results, in this case the read data.
        INIT_SIMPLE_TPM2B_SIZE( readData );
        rval = Tss2_Sys_NV_Read_Complete( sysContext, &readData );
        CheckPassed( rval );

        DebugPrintf( NO_PREFIX, "Decrypted read data = " );
        DEBUG_PRINT_BUFFER( NO_PREFIX, &readData.t.buffer[0], (UINT32 )readData.t.size );

        // Check that write and read data are equal.
        if( memcmp( (void *)&readData.t.buffer[0],
                (void *)&writeData.t.buffer[0], readData.t.size ) )
        {
            DebugPrintf( NO_PREFIX, "ERROR!! read data not equal to written data\n" );
            Cleanup();
        }

        rval = Tss2_Sys_FlushContext( sysContext,
                encryptDecryptSession->sessionHandle );
        CheckPassed( rval );

        rval = EndAuthSession( encryptDecryptSession );
        CheckPassed( rval );
    }

    // Set authorization for NV undefine command.
    nvUndefineAuth.sessionHandle = TPM_RS_PW;
    nvUndefineAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&nvUndefineAuth.sessionAttributes ) ) = 0;
    nvUndefineAuth.hmac.t.size = 0;

    // Undefine NV index.
    rval = Tss2_Sys_NV_UndefineSpace( sysContext,
            TPM_RH_PLATFORM, TPM20_INDEX_TEST1, &nvUndefineAuths, 0 );
    CheckPassed( rval );
}

void GetSetDecryptParamTests()
{
    TPM2B_MAX_NV_BUFFER nvWriteData = { { 4, { 0xde, 0xad, 0xbe, 0xef, } } };
    TPM2B_MAX_NV_BUFFER nvWriteData1 = { { 4, { 0x01, 0x01, 0x02, 0x03, } } };
    const uint8_t *decryptParamBuffer;
    size_t decryptParamSize;
    size_t cpBufferUsedSize1, cpBufferUsedSize2;
    const uint8_t *cpBuffer1, *cpBuffer2;
    TSS2_RC rval;
    int i;
    TSS2_SYS_CONTEXT *decryptParamTestSysContext;

    DebugPrintf( NO_PREFIX, "\nGET/SET DECRYPT PARAM TESTS:\n" );

    // Create two sysContext structures.
    decryptParamTestSysContext = InitSysContext( MAX_NV_BUFFER_SIZE, resMgrTctiContext, &abiVersion );
    if( decryptParamTestSysContext == 0 )
    {
        InitSysContextFailure();
    }

    // Test for bad sequence:  Tss2_Sys_GetDecryptParam
    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, &decryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE );

    // Test for bad sequence:  Tss2_Sys_SetDecryptParam
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 4, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE );

    // NOTE:  Two tests for BAD_SEQUENCE for GetDecryptParam and SetDecryptParam after ExecuteAsync
    // are in the GetSetEncryptParamTests function, just because it's easier to do this way.

    // Do Prepare.
    rval = Tss2_Sys_NV_Write_Prepare( decryptParamTestSysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData1, 0x55aa );
    CheckPassed( rval );

    // Test for bad reference:  Tss2_Sys_GetDecryptParam
    rval = Tss2_Sys_GetDecryptParam( 0, &decryptParamSize, &decryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, 0, &decryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );


    // Test for bad reference:  Tss2_Sys_SetDecryptParam
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 4, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_SetDecryptParam( 0, 4, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );


    // Test for bad size.
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 5, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE );

    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 3, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE );

    // Test for good size.
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 4, &( nvWriteData.t.buffer[0] ) );
    CheckPassed( rval );

    // Make sure that the set operation really did the right thing.
    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, &decryptParamBuffer );
    CheckPassed( rval );
    for( i = 0; i < 4; i++ )
    {
        if( decryptParamBuffer[i] != nvWriteData.t.buffer[i] )
        {
            DebugPrintf( NO_PREFIX, "ERROR!!  decryptParamBuffer[%d] s/b: %2.2x, was: %2.2x\n", i, nvWriteData.t.buffer[i], decryptParamBuffer[i] );
            Cleanup();
        }
    }

    rval = Tss2_Sys_GetCpBuffer( decryptParamTestSysContext, &cpBufferUsedSize1, &cpBuffer1 );
    CheckPassed( rval );

#ifdef DEBUG
    DebugPrintf( NO_PREFIX, "cpBuffer = ");
#endif
    DEBUG_PRINT_BUFFER( NO_PREFIX, (UINT8 *)cpBuffer1, cpBufferUsedSize1 );

    // Test for no decrypt param.
    rval = Tss2_Sys_NV_Read_Prepare( decryptParamTestSysContext, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, sizeof( nvWriteData ) - 2, 0 );
    CheckPassed( rval );

    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, &decryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_NO_DECRYPT_PARAM );

    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 4, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_NO_DECRYPT_PARAM );

    // Null decrypt param.
    rval = Tss2_Sys_NV_Write_Prepare( decryptParamTestSysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, 0, 0x55aa );
    CheckPassed( rval );

    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, &decryptParamBuffer );
    CheckPassed( rval );

    // Check that size == 0.
    if( decryptParamSize != 0 )
    {
        DebugPrintf( NO_PREFIX, "ERROR!!  decryptParamSize s/b: 0, was: %u\n", (unsigned int)decryptParamSize );
        Cleanup();
    }

    // Test for insufficient size.
    rval = Tss2_Sys_GetCpBuffer( decryptParamTestSysContext, &cpBufferUsedSize2, &cpBuffer2 );
    CheckPassed( rval );
    nvWriteData.t.size = MAX_NV_BUFFER_SIZE -
            CHANGE_ENDIAN_DWORD( ( (TPM20_Header_In *)( ( (_TSS2_SYS_CONTEXT_BLOB *)decryptParamTestSysContext )->tpmInBuffPtr ) )->commandSize ) +
            1;
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, nvWriteData.t.size, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_INSUFFICIENT_CONTEXT );

    // Test that one less will work.  This tests that we're checking the correct corner case.
    nvWriteData.t.size -= 1;
    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, nvWriteData.t.size, &( nvWriteData.t.buffer[0] ) );
    CheckPassed( rval );


    rval = Tss2_Sys_NV_Write_Prepare( decryptParamTestSysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, 0, 0x55aa );
    CheckPassed( rval );

    rval = Tss2_Sys_GetDecryptParam( decryptParamTestSysContext, &decryptParamSize, &decryptParamBuffer );
    CheckPassed( rval );

    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 4, &( nvWriteData.t.buffer[0] ) );
    CheckPassed( rval );

    rval = Tss2_Sys_GetCpBuffer( decryptParamTestSysContext, &cpBufferUsedSize2, &cpBuffer2 );
    CheckPassed( rval );

#ifdef DEBUG
    DebugPrintf( NO_PREFIX, "cpBuffer = ");
#endif
    DEBUG_PRINT_BUFFER( NO_PREFIX, (UINT8 *)cpBuffer2, cpBufferUsedSize2 );

    if( cpBufferUsedSize1 != cpBufferUsedSize2 )
    {
        DebugPrintf( NO_PREFIX, "ERROR!!  cpBufferUsedSize1(%x) != cpBufferUsedSize2(%x)\n", (UINT32)cpBufferUsedSize1, (UINT32)cpBufferUsedSize2 );
        Cleanup();
    }
    for( i = 0; i < (int)cpBufferUsedSize1; i++ )
    {
        if( cpBuffer1[i] != cpBuffer2[i] )
        {
            DebugPrintf( NO_PREFIX, "ERROR!! cpBufferUsedSize1[%d] s/b: %2.2x, was: %2.2x\n", i, cpBuffer1[i], cpBuffer2[i] );
            Cleanup();
        }
    }

    // Test case of zero sized decrypt param, another case of bad size.
    nvWriteData1.t.size = 0;
    rval = Tss2_Sys_NV_Write_Prepare( decryptParamTestSysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData1, 0x55aa );
    CheckPassed( rval );

    rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 1, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE );

    TeardownSysContext( &decryptParamTestSysContext );
}

void SysInitializeTests()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;

    // NOTE: this should never be done in real applications.
    // It is only done here for test purposes.
    TSS2_TCTI_CONTEXT_INTEL tctiContextIntel;

    DebugPrintf( NO_PREFIX, "\nSYS INITIALIZE TESTS:\n" );

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)0, 10, (TSS2_TCTI_CONTEXT *)1, (TSS2_ABI_VERSION *)1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)1, 10, (TSS2_TCTI_CONTEXT *)0, (TSS2_ABI_VERSION *)1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)1, 10, (TSS2_TCTI_CONTEXT *)1, (TSS2_ABI_VERSION *)0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)1, 10, (TSS2_TCTI_CONTEXT *)1, (TSS2_ABI_VERSION *)1 );
    CheckFailed( rval, TSS2_SYS_RC_INSUFFICIENT_CONTEXT );

    // NOTE: don't do this in real applications.
    tctiContextIntel.transmit = (TCTI_TRANSMIT_PTR)0;
    tctiContextIntel.receive = (TCTI_RECEIVE_PTR)1;

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)1, sizeof( _TSS2_SYS_CONTEXT_BLOB ), (TSS2_TCTI_CONTEXT *)&tctiContextIntel, (TSS2_ABI_VERSION *)1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_TCTI_STRUCTURE );

    // NOTE: don't do this in real applications.
    tctiContextIntel.transmit = (TCTI_TRANSMIT_PTR)1;
    tctiContextIntel.receive = (TCTI_RECEIVE_PTR)0;

    rval = Tss2_Sys_Initialize( (TSS2_SYS_CONTEXT *)1, sizeof( _TSS2_SYS_CONTEXT_BLOB ), (TSS2_TCTI_CONTEXT *)&tctiContextIntel, (TSS2_ABI_VERSION *)1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_TCTI_STRUCTURE );
}

void SysFinalizeTests()
{
    DebugPrintf( NO_PREFIX, "\nSYS FINALIZE TESTS:\n" );

    Tss2_Sys_Finalize( 0 );

    // Note:  other cases tested by other tests.
}

void GetContextSizeTests()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TSS2_SYS_CONTEXT *testSysContext;

    DebugPrintf( NO_PREFIX, "\nSYS GETCONTEXTSIZE TESTS:\n" );

    testSysContext = InitSysContext( 9, resMgrTctiContext, &abiVersion );
    if( testSysContext == 0 )
    {
        InitSysContextFailure();
    }

    rval = Tss2_Sys_Startup( testSysContext, TPM_SU_CLEAR );
    CheckFailed( rval, TSS2_SYS_RC_INSUFFICIENT_CONTEXT );

	rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
	CheckPassed( rval );

    // Note:  other cases tested by other tests.

    TeardownSysContext( &testSysContext );
}

void GetTctiContextTests()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TSS2_SYS_CONTEXT *testSysContext;
    TSS2_TCTI_CONTEXT *tctiContext;

    DebugPrintf( NO_PREFIX, "\nSYS GETTCTICONTEXT TESTS:\n" );

    testSysContext = InitSysContext( 9, resMgrTctiContext, &abiVersion );
    if( testSysContext == 0 )
    {
        InitSysContextFailure();
    }

    rval = Tss2_Sys_GetTctiContext( testSysContext, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    rval = Tss2_Sys_GetTctiContext( 0, &tctiContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    TeardownSysContext( &testSysContext );
}

void PrepareTests()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TSS2_SYS_CONTEXT *testSysContext;

    DebugPrintf( NO_PREFIX, "\nSYS PREPARE TESTS:\n" );

    testSysContext = InitSysContext( 0, resMgrTctiContext, &abiVersion );
    if( testSysContext == 0 )
    {
        InitSysContextFailure();
    }

    // Test for bad reference.
    rval = Tss2_Sys_GetTestResult_Prepare( 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    // Test for bad sequence:  after ExecuteAsync
    rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteAsync( testSysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE );

    rval = Tss2_Sys_ExecuteFinish( testSysContext, -1 );
    CheckPassed( rval );

    // Test for bad sequence:  after Execute
    rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_Execute( testSysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_GetTestResult_Prepare( testSysContext );
    CheckPassed( rval );

    // Test for other NULL params
    rval = Tss2_Sys_Create_Prepare( testSysContext, 0xffffffff, 0, 0, 0, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE );

    TeardownSysContext( &testSysContext );
}

void  RmZeroSizedResponseTest()
{
    SESSION *encryptSession;
    TPM2B_NONCE nonceCaller;
    TPMT_SYM_DEF symmetric;
	TSS2_RC rval = TSS2_RC_SUCCESS;

    //
    // Tests what happens in RM when receive comes back with 0 sized response.
    // This happens when a command is sent to the simulator but the simulator
    // isn't "powered on".
    // Added this test because this took me a while to understand, and I
    // never want to have to debug this again.
    //

    DebugPrintf( NO_PREFIX, "\nRM ZERO SIZED RESPONSE TEST:\n" );

    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );

    nonceCaller.t.size = 1;
    nonceCaller.t.buffer[0] = 0xa5;

    // AES encryption/decryption and CFB mode.
    symmetric.algorithm = TPM_ALG_AES;
    symmetric.keyBits.aes = 128;
    symmetric.mode.aes = TPM_ALG_CFB;

    // Start policy session for encrypt session.
    rval = StartAuthSessionWithParams( &encryptSession,
            TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, 0, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckFailed( rval, TSS2_TCTI_RC_IO_ERROR );
}


void CmdRspAuthsTests()
{
    SESSION *encryptSession, *decryptSession, *auditSession;
    TPM2B_NONCE nonceCaller, nonceTpm;
    TPMT_SYM_DEF symmetric;
	TSS2_RC rval = TSS2_RC_SUCCESS;
    int i;
    TPM2B_ENCRYPTED_SECRET	encryptedSalt;
	UINT32 savedMaxCommandSize, savedResponseSize;

    TSS2_SYS_CONTEXT *otherSysContext;
    TPM_HANDLE testSessionHandle;

    TPMS_AUTH_COMMAND encryptCmdAuth, decryptCmdAuth, auditCmdAuth;
    TPMS_AUTH_COMMAND *cmdAuthArray[3] = { &encryptCmdAuth, &decryptCmdAuth, &auditCmdAuth };
    TSS2_SYS_CMD_AUTHS cmdAuths = { 3, &cmdAuthArray[0] };

    TPMS_AUTH_RESPONSE encryptRspAuth, decryptRspAuth, auditRspAuth;
    TPMS_AUTH_RESPONSE *rspAuthArray[3] =
            { &encryptRspAuth, &decryptRspAuth, &auditRspAuth };
    TSS2_SYS_RSP_AUTHS rspAuths = { 3, &rspAuthArray[0] };

    DebugPrintf( NO_PREFIX, "\nSETCMDAUTHS TESTS:\n" );

    nonceCaller.t.size = SHA256_DIGEST_SIZE;

    for( i = 0; i < nonceCaller.t.size; i++ )
    {
        nonceCaller.t.buffer[i] = 0xa5;
    }

    // AES encryption/decryption and CFB mode.
    symmetric.algorithm = TPM_ALG_AES;
    symmetric.keyBits.aes = 128;
    symmetric.mode.aes = TPM_ALG_CFB;

    // Start encrypt session.
    rval = StartAuthSessionWithParams( &encryptSession,
            TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, 0, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval ); // #1

    // Start decrypt session.
    rval = StartAuthSessionWithParams( &decryptSession,
            TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, 0, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval );  // #2

    // Start audit session.
    rval = StartAuthSessionWithParams( &auditSession,
            TPM_RH_NULL, 0, TPM_RH_NULL, 0, &nonceCaller, 0, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256, resMgrTctiContext );
    CheckPassed( rval ); // #3

    encryptCmdAuth.sessionHandle = encryptSession->sessionHandle;
    encryptCmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&encryptCmdAuth.sessionAttributes ) ) = 0;
    encryptCmdAuth.sessionAttributes.encrypt = 1;
    encryptCmdAuth.hmac.t.size = 0;

    decryptCmdAuth.sessionHandle = decryptSession->sessionHandle;
    decryptCmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&decryptCmdAuth.sessionAttributes ) ) = 0;
    decryptCmdAuth.sessionAttributes.decrypt = 1;
    decryptCmdAuth.hmac.t.size = 0;

    auditCmdAuth.sessionHandle = auditSession->sessionHandle;
    auditCmdAuth.nonce.t.size = 0;
    *( (UINT8 *)((void *)&auditCmdAuth.sessionAttributes ) ) = 0;
    auditCmdAuth.sessionAttributes.audit = 1;
    auditCmdAuth.hmac.t.size = 0;

    // Test for bad sequence.
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #4

    encryptedSalt.t.size = 0;
    rval = Tss2_Sys_StartAuthSession_Prepare( sysContext,
            TPM_RH_NULL, TPM_RH_NULL, &nonceCaller, &encryptedSalt, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256 );
    CheckPassed( rval ); // #5

    // Test for bad reference.
    rval = Tss2_Sys_SetCmdAuths( 0, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #6

    rval = Tss2_Sys_SetCmdAuths( sysContext, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #7

    // Test for count == 0; this should pass.
    cmdAuths.cmdAuthsCount= 0;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval ); // #8

    // Test for bad value.
    cmdAuths.cmdAuthsCount= 3;
    cmdAuthArray[0] = 0;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); // #9

    cmdAuthArray[0] = &encryptCmdAuth;
    cmdAuthArray[1] = 0;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); // #10

    cmdAuthArray[1] = &decryptCmdAuth;
    cmdAuthArray[2] = 0;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); // #11
    cmdAuthArray[2] = &auditCmdAuth;

    // Test for insufficient context.
    cmdAuths.cmdAuthsCount= 0;
    savedMaxCommandSize = ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize;
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = sizeof( TPM20_Header_In ) + 3 * sizeof( TPM_HANDLE ) - 1;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval ); // #12

    cmdAuths.cmdAuthsCount= 0;
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = sizeof( TPM20_Header_In ) + 3 * sizeof( TPM_HANDLE );
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval );// #13

    cmdAuths.cmdAuthsCount= 3;
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = sizeof( TPM20_Header_In ) + 3 * sizeof( TPM_HANDLE );
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_INSUFFICIENT_CONTEXT ); // #14

    // Do successful one; use this to get size of command.
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = savedMaxCommandSize;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval ); // #15

    // Then set maxCommandSize to the the previously gotten commandSize - 1.  This should fail.
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = GetCommandSize( sysContext ) - 1;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckFailed( rval, TSS2_SYS_RC_INSUFFICIENT_CONTEXT ); // #16

    // Reset size of sysContext.
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = savedMaxCommandSize;

    // Setup for response auths test.
    ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->maxCommandSize = CHANGE_ENDIAN_DWORD( savedMaxCommandSize );
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval ); // #15

	DebugPrintf( NO_PREFIX, "\nGETRSPAUTHS TESTS:\n" );

    // Test for bad sequence.
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #1

    otherSysContext = InitSysContext( 0, resMgrTctiContext, &abiVersion );
    if( otherSysContext == 0 )
    {
        InitSysContextFailure();
    }

    //
    // Test for command that failed:  invalid handle.
    //
    rval = Tss2_Sys_StartAuthSession_Prepare( otherSysContext,
            0xffffffff, TPM_RH_NULL, &nonceCaller, &encryptedSalt, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256 );
    CheckPassed( rval ); // #2

    rval = Tss2_Sys_Execute( otherSysContext );
    CheckFailed( rval, (TPM_RC_VALUE | TPM_RC_1 | TPM_RC_H) ); // #3

    rval = Tss2_Sys_GetRspAuths( otherSysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #4

    //
    // Test for command that can never take sessions.
    //
    rval = Tss2_Sys_ReadClock_Prepare( otherSysContext );
    CheckPassed( rval ); // #5

    rval = Tss2_Sys_Execute( otherSysContext );
    CheckPassed( rval ); // #6

    rval = Tss2_Sys_GetRspAuths( otherSysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #7

    // Setup for testing for bad references and other conditions.
    rval = Tss2_Sys_StartAuthSession_Prepare( sysContext,
            TPM_RH_NULL, TPM_RH_NULL, &nonceCaller, &encryptedSalt, TPM_SE_HMAC,
            &symmetric, TPM_ALG_SHA256 );
    CheckPassed( rval ); // #8

    cmdAuths.cmdAuthsCount = 2;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &cmdAuths );
    CheckPassed( rval ); // #9

	rval = Tss2_Sys_Execute( sysContext );
    CheckPassed( rval ); // #10

    // Test for bad reference.
    rval = Tss2_Sys_GetRspAuths( 0, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #11

    rval = Tss2_Sys_GetRspAuths( sysContext, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #12

    // Test for bad count.
    rspAuths.rspAuthsCount = 0;
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); // #13

    // Test for non-matching count: specified count doesn't
    // match returned count.
    rspAuths.rspAuthsCount = 1;
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_INVALID_SESSIONS ); // #14

    // Test for non-matching count: cmd auth count doesn't
    // match returned auth count.
    rspAuths.rspAuthsCount = 3;
    savedResponseSize = CHANGE_ENDIAN_DWORD( ( (TPM20_Header_Out *)( ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->tpmOutBuffPtr ) )->responseSize );
    ( (TPM20_Header_Out *)( ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->tpmOutBuffPtr ) )->responseSize = CHANGE_ENDIAN_DWORD( savedResponseSize - 5 );
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_INVALID_SESSIONS ); // #15

    // Test for malformed response.
    rspAuths.rspAuthsCount = 2;
    ( (TPM20_Header_Out *)( ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->tpmOutBuffPtr ) )->responseSize = CHANGE_ENDIAN_DWORD( savedResponseSize - 7 );
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckFailed( rval, TSS2_SYS_RC_MALFORMED_RESPONSE ); // #16

    // Ths one should pass.
    ( (TPM20_Header_Out *)( ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->tpmOutBuffPtr ) )->responseSize = CHANGE_ENDIAN_DWORD( savedResponseSize );
    rval = Tss2_Sys_GetRspAuths( sysContext, &rspAuths );
    CheckPassed( rval ); // #17

    // Check for bad sequence.
    INIT_SIMPLE_TPM2B_SIZE( nonceTpm );
    rval = Tss2_Sys_StartAuthSession_Complete( sysContext,
            &testSessionHandle, &nonceTpm );
    CheckPassed( rval ); // #17

    // Now delete sessions.
    rval = EndAuthSession( encryptSession );
    CheckPassed( rval );

    rval = EndAuthSession( decryptSession );
    CheckPassed( rval );

    rval = EndAuthSession( auditSession );
    CheckPassed( rval );
}

void GetSetEncryptParamTests()
{
    TPM2B_MAX_NV_BUFFER nvWriteData = { { 4, { 0xde, 0xad, 0xbe, 0xef, } } };
    const uint8_t *encryptParamBuffer;
    const uint8_t encryptParamBuffer1[4] = { 01, 02, 03, 04 };
    size_t encryptParamSize;
    TSS2_RC rval;
    int i;
    TPM2B_DIGEST authPolicy;
    TPMA_NV nvAttributes;
    TPM2B_AUTH  nvAuth;

    TPMS_AUTH_COMMAND sessionData = { TPM_RS_PW, };
    TPMS_AUTH_RESPONSE sessionDataOut;
    TPMS_AUTH_COMMAND *sessionDataArray[1] = { &sessionData };
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1] = { &sessionDataOut };
    TSS2_SYS_CMD_AUTHS sessionsData = { 1, &sessionDataArray[0] };
    TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, &sessionDataOutArray[0] };

    TPM2B_MAX_NV_BUFFER nvReadData;
    const uint8_t 		*cpBuffer;

    DebugPrintf( NO_PREFIX, "\nGET/SET ENCRYPT PARAM TESTS:\n" );

    // Do Prepare.
    rval = Tss2_Sys_NV_Write_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
    CheckPassed( rval ); // #1

    // Test for bad sequence
    rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize, &encryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #2

    rval = Tss2_Sys_SetEncryptParam( sysContext, 4, &( nvWriteData.t.buffer[0] ) );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #3

    // Create NV index

    // Set empty policy and auth value.
    authPolicy.t.size = 0;
    nvAuth.t.size = 0;

    // Now set the attributes.
    *(UINT32 *)( (void *)&nvAttributes ) = 0;
    nvAttributes.TPMA_NV_AUTHREAD = 1;
    nvAttributes.TPMA_NV_AUTHWRITE = 1;
    nvAttributes.TPMA_NV_PLATFORMCREATE = 1;

    rval = DefineNvIndex( TPM_RH_PLATFORM, TPM_RS_PW, &nvAuth, &authPolicy,
            TPM20_INDEX_PASSWORD_TEST, TPM_ALG_SHA1, nvAttributes, 32  );
    CheckPassed( rval ); // #4

    // Write the index.
    rval = Tss2_Sys_NV_Write_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0 );
    CheckPassed( rval ); // #5

    // NOTE: add GetCpBuffer tests here, just because its easier.
    rval = Tss2_Sys_GetCpBuffer( 0, (size_t *)4, (const uint8_t **)4 );
	CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #6

    rval = Tss2_Sys_GetCpBuffer( sysContext, (size_t *)0, (const uint8_t **)4 );
	CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #7

    rval = Tss2_Sys_GetCpBuffer( sysContext, (size_t *)4, (const uint8_t **)0 );
	CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #8


    rval = Tss2_Sys_SetCmdAuths( sysContext, &sessionsData );
    CheckPassed( rval ); // #9

    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval ); // #10

    // NOTE: Stick two tests for BAD_SEQUENCE for GetDecryptParam and SetDecryptParam here, just
    // because it's easier to do this way.
    rval = Tss2_Sys_GetDecryptParam( sysContext, (size_t *)4, (const uint8_t **)4 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #11

    rval = Tss2_Sys_SetDecryptParam( sysContext, 10, (uint8_t *)4 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #12

    // NOTE: Stick test for BAD_SEQUENCE for GetCpBuffer here, just
    // because it's easier to do this way.
    rval = Tss2_Sys_GetCpBuffer( sysContext, (size_t *)4, &cpBuffer );
	CheckFailed( rval, TSS2_SYS_RC_BAD_SEQUENCE ); // #13

    // Now finish the write command so that TPM isn't stuck trying
    // to send a response.
    rval = Tss2_Sys_ExecuteFinish( sysContext, -1 );
    CheckPassed( rval ); // #14

    // Test GetEncryptParam for no encrypt param case.
    rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize, &encryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_NO_ENCRYPT_PARAM ); // #15

    // Test SetEncryptParam for no encrypt param case.
    rval = Tss2_Sys_SetEncryptParam( sysContext, encryptParamSize, encryptParamBuffer1 );
    CheckFailed( rval, TSS2_SYS_RC_NO_ENCRYPT_PARAM ); // #16

    // Now read it and do tests on get/set encrypt functions
    rval = Tss2_Sys_NV_Read_Prepare( sysContext, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, 4, 0 );
    CheckPassed( rval ); // #17

    INIT_SIMPLE_TPM2B_SIZE( nvReadData );
    rval = Tss2_Sys_NV_Read( sysContext, TPM20_INDEX_PASSWORD_TEST,
            TPM20_INDEX_PASSWORD_TEST, &sessionsData, 4, 0, &nvReadData, &sessionsDataOut );
    CheckPassed( rval ); // #18

    rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize, &encryptParamBuffer );
    CheckPassed( rval ); // #19

    // Test case of encryptParamSize being too small.
    encryptParamSize--;
    rval = Tss2_Sys_SetEncryptParam( sysContext, encryptParamSize, encryptParamBuffer1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE ); // #20
    encryptParamSize += 2;

    // Size too large...
    rval = Tss2_Sys_SetEncryptParam( sysContext, encryptParamSize, encryptParamBuffer1 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE ); // #21

    encryptParamSize--;
    rval = Tss2_Sys_SetEncryptParam( sysContext, encryptParamSize, encryptParamBuffer1 );
    CheckPassed( rval ); // #22

    rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize, &encryptParamBuffer );
    CheckPassed( rval ); // #23

    // Test that encryptParamBuffer is the same as encryptParamBuffer1
    for( i = 0; i < 4; i++ )
    {
        if( encryptParamBuffer[i] != encryptParamBuffer1[i] )
        {
            DebugPrintf( NO_PREFIX, "ERROR!! encryptParamBuffer[%d] s/b: %2.2x, was: %2.2x\n", i, encryptParamBuffer[i], encryptParamBuffer1[i] );
            Cleanup();
        }
    }

    rval = Tss2_Sys_NV_UndefineSpace( sysContext, TPM_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST, &sessionsData, 0 );
    CheckPassed( rval ); // #24


    // Test for bad reference
    rval = Tss2_Sys_GetEncryptParam( 0, &encryptParamSize, &encryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #25

    rval = Tss2_Sys_GetEncryptParam( sysContext, 0, &encryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #26

    rval = Tss2_Sys_GetEncryptParam( sysContext, &encryptParamSize, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #27

    rval = Tss2_Sys_SetEncryptParam( sysContext, 4, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #28

    rval = Tss2_Sys_SetEncryptParam( 0, 4, encryptParamBuffer );
    CheckFailed( rval, TSS2_SYS_RC_BAD_REFERENCE ); // #29
}

void TestRM()
{
    TSS2_TCTI_CONTEXT *otherResMgrTctiContext = 0;
    TSS2_SYS_CONTEXT *otherSysContext;
    TPM2B_SENSITIVE_CREATE  inSensitive;
    TPM2B_PUBLIC            inPublic;
    TPM2B_DATA              outsideInfo;
    TPML_PCR_SELECTION      creationPCR;
    TPMS_AUTH_COMMAND sessionData;
    TPMS_AUTH_RESPONSE sessionDataOut;
    TSS2_SYS_CMD_AUTHS sessionsData;

    TSS2_SYS_RSP_AUTHS sessionsDataOut;
    TPM2B_NAME name;
    TPM2B_PUBLIC outPublic;
    TPM2B_CREATION_DATA creationData;
    TPM2B_DIGEST creationHash;
    TPMT_TK_CREATION creationTicket;

    TPMS_AUTH_COMMAND *sessionDataArray[1];
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1];
    TSS2_RC rval = TSS2_RC_SUCCESS;

    TPMS_CONTEXT context;
    TSS2_TCTI_CONTEXT *tctiContext;

    TPMI_DH_CONTEXT loadedHandle, newHandle, newNewHandle, newHandleDummy;
    TPMS_CONTEXT    newContext;
    char otherResMgrInterfaceName[] = "Test RM Resource Manager";

    DebugPrintf( NO_PREFIX, "\nRM TESTS:\n" );

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;
    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.data.t.size = 0;
    inSensitive.t.size = loadedSha1KeyAuth.b.size + 2;

    inPublic.t.publicArea.type = TPM_ALG_RSA;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;

    // First clear attributes bit field.
    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.restricted = 1;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;
    inPublic.t.publicArea.objectAttributes.decrypt = 1;
    inPublic.t.publicArea.objectAttributes.fixedTPM = 1;
    inPublic.t.publicArea.objectAttributes.fixedParent = 1;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 1;

    inPublic.t.publicArea.authPolicy.t.size = 0;

    inPublic.t.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_ECB;
    inPublic.t.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 1024;
    inPublic.t.publicArea.parameters.rsaDetail.exponent = 0;

    inPublic.t.publicArea.unique.rsa.t.size = 0;

    outsideInfo.t.size = 0;
    creationPCR.count = 0;

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    rval = InitSocketTctiContext( &rmInterfaceConfig, &otherResMgrTctiContext);
    if( rval != TSS2_RC_SUCCESS )
    {
        DebugPrintf( NO_PREFIX, "Resource Mgr, %s, failed initialization: 0x%x.  Exiting...\n", otherResMgrInterfaceName, rval );
        Cleanup();
        return;
    }

    otherSysContext = InitSysContext( 0, otherResMgrTctiContext, &abiVersion );
    if( otherSysContext == 0 )
    {
        InitSysContextFailure();
    }

    // TEST WITH AN INVALID COMMAND CODE.

    rval = Tss2_Sys_Startup_Prepare( sysContext, TPM_SU_CLEAR );
    CheckPassed(rval);

    //
    // Alter the CC by altering the CC field in sysContext.
    //
    // WARNING:  This is something only a test application should do. Do
    // not use this as sample code.
    //
    ((TPM20_Header_In *)( ( (_TSS2_SYS_CONTEXT_BLOB *)sysContext )->tpmInBuffPtr) )->commandCode = TPM_CC_FIRST - 1;
    rval = Tss2_Sys_Execute( sysContext );
    CheckFailed( rval, TPM_RC_COMMAND_CODE );

    // TEST OWNERSHIP

    // Try to access a key created by the first TCTI context.
    sessionData.hmac.t.size = 2;
    sessionData.hmac.t.buffer[0] = 0x00;
    sessionData.hmac.t.buffer[1] = 0xff;

    inPublic.t.publicArea.type = TPM_ALG_RSA;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;

    // First clear attributes bit field.
    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.restricted = 1;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;
    inPublic.t.publicArea.objectAttributes.decrypt = 1;
    inPublic.t.publicArea.objectAttributes.fixedTPM = 1;
    inPublic.t.publicArea.objectAttributes.fixedParent = 1;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 1;

    inPublic.t.publicArea.authPolicy.t.size = 0;

    inPublic.t.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_ECB;
    inPublic.t.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 2048;
    inPublic.t.publicArea.parameters.rsaDetail.exponent = 0;

    inPublic.t.publicArea.unique.rsa.t.size = 0;

    outsideInfo.t.size = 0;


    // This one should pass, because the same context is allowed to save the context.
    rval = Tss2_Sys_ContextSave( sysContext, handle2048rsa, &context );
    CheckPassed( rval );

    // This one should pass, since we saved the context first.
    rval = Tss2_Sys_ContextLoad( otherSysContext, &context, &loadedHandle );
    CheckPassed( rval );

    rval = Tss2_Sys_FlushContext( otherSysContext, loadedHandle );
    CheckPassed( rval );

    // NOW, DO SOME LOCALITY TESTS

    // Test with null tctiContext ptr.
    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->setLocality)( 0, 0 );
    CheckFailed( rval, TSS2_TCTI_RC_BAD_REFERENCE );

    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->setLocality)( otherResMgrTctiContext, 0 );
    CheckPassed( rval );

    // Now try changing localities between send and receive.
    rval = Tss2_Sys_ContextLoad( otherSysContext, &context, &loadedHandle );
    CheckPassed( rval );

    rval = Tss2_Sys_FlushContext_Prepare( otherSysContext, loadedHandle );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteAsync( otherSysContext );
    CheckPassed( rval );

    // This should fail because locality is changing between send and receive.
    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->setLocality)( otherResMgrTctiContext, 1 );
    CheckFailed( rval, TSS2_TCTI_RC_BAD_SEQUENCE );

    rval = Tss2_Sys_ExecuteFinish( otherSysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckPassed( rval );

    // NOW, DO SOME CANCEL TESTS

    rval = Tss2_Sys_GetTctiContext( sysContext, &tctiContext );
    CheckPassed( rval );

    // Try cancel with null tctiContext ptr.
    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->cancel)( 0 );
    CheckFailed( rval, TSS2_TCTI_RC_BAD_REFERENCE );

    // Try cancel when no commands are pending.
    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->cancel)( otherResMgrTctiContext );
    CheckFailed( rval, TSS2_TCTI_RC_BAD_SEQUENCE );

    // Then try cancel with a pending command:  send cancel before blocking _Finish call.
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 2048;
    rval = Tss2_Sys_CreatePrimary_Prepare( sysContext, TPM_RH_PLATFORM, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR );
    CheckPassed( rval );

    //
    // NOTE: there are race conditions in tests that use cancel and
    // are expecting to receive the CANCEL response code.  The tests
    // typically pass, but may occasionally fail on the order of
    // 1 out of 500 or so test passes.
    //
    // The OS could delay the test app long enough for the TPM to
    // complete the CreatePrimary before the test app gets to run
    // again.  To make these tests robust would require some way to
    // create a critical section in the test app.
    //
    sessionData.hmac.t.size = 0;
    sessionData.nonce.t.size = 0;
    rval = Tss2_Sys_SetCmdAuths( sysContext, &sessionsData );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval );

    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)tctiContext)->cancel)( tctiContext );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TPM_RC_CANCELED );

     // Then try cancel with a pending command:  send cancel after non-blocking _Finish call.
    rval = Tss2_Sys_CreatePrimary_Prepare( sysContext, TPM_RH_PLATFORM, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR );
    CheckPassed( rval );

    rval = Tss2_Sys_SetCmdAuths( sysContext, &sessionsData );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteFinish( sysContext, 0 );
    CheckFailed( rval, TSS2_TCTI_RC_TRY_AGAIN );

    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)tctiContext)->cancel)( tctiContext );
    CheckPassed( rval );

	rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckFailed( rval, TPM_RC_CANCELED );

    // Then try cancel from a different connection:  it should just get a sequence error.
    rval = Tss2_Sys_CreatePrimary_Prepare( sysContext, TPM_RH_PLATFORM, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR );
    CheckPassed( rval );

    rval = Tss2_Sys_SetCmdAuths( sysContext, &sessionsData );
    CheckPassed( rval );

    rval = Tss2_Sys_ExecuteAsync( sysContext );
    CheckPassed( rval );

    rval = (((TSS2_TCTI_CONTEXT_COMMON_V1 *)otherResMgrTctiContext)->cancel)( otherResMgrTctiContext );
    CheckFailed( rval, TSS2_TCTI_RC_BAD_SEQUENCE );

    rval = Tss2_Sys_ExecuteFinish( sysContext, TSS2_TCTI_TIMEOUT_BLOCK );
    CheckPassed( rval );

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( name );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    creationHash.t.size = sizeof( creationHash );
    rval = Tss2_Sys_CreatePrimary_Complete( sysContext, &newHandle, &outPublic, &creationData,
            &creationHash, &creationTicket, &name );
    CheckPassed( rval );

    //
    // Now try saving context for object and loading it using a different connection.
    //

    // First save context.
    rval = Tss2_Sys_ContextSave( sysContext, newHandle, &newContext );
    CheckPassed( rval );

    //
    // Now create an object with different hierarchy.  This will make sure that
    // RM is getting correct hierarchy in it's table.
    // NOTE:  this test can only be verified by looking at RM output.
    //
	outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( name );
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_ENDORSEMENT, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &newHandleDummy, &outPublic, &creationData, &creationHash,
			&creationTicket, &name, &sessionsDataOut );
    CheckPassed( rval );

    // Now try loading the context using a different connection.
    rval = Tss2_Sys_ContextLoad( otherSysContext, &newContext, &newNewHandle );
    CheckPassed( rval );

    // Flush original connection's object.
    rval = Tss2_Sys_FlushContext( sysContext, newHandle );
    CheckPassed( rval );

    // Now flush new object from other connection.  Should work.
    rval = Tss2_Sys_FlushContext( otherSysContext, newNewHandle );
    CheckPassed( rval );

    // Now flush dummy object.
    rval = Tss2_Sys_FlushContext( sysContext, newHandleDummy );
    CheckPassed( rval );

    TeardownTctiContext( &otherResMgrTctiContext );

    TeardownSysContext( &otherSysContext );
}

void EcEphemeralTest()
{
    TSS2_RC rval = TSS2_RC_SUCCESS;
    TPM2B_ECC_POINT Q;
    UINT16 counter;

    DebugPrintf( NO_PREFIX, "\nEC Ephemeral TESTS:\n" );

    // Test SAPI for case of Q size field not being set to 0.
    INIT_SIMPLE_TPM2B_SIZE( Q );
    rval = Tss2_Sys_EC_Ephemeral( sysContext, 0, TPM_ECC_BN_P256, &Q, &counter, 0 );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE );

    Q.t.size = 0;
    rval = Tss2_Sys_EC_Ephemeral( sysContext, 0, TPM_ECC_BN_P256, &Q, &counter, 0 );
    CheckPassed( rval );
}


void AbiVersionTests()
{
    UINT32 contextSize = 1000;
    TSS2_RC rval;
    TSS2_SYS_CONTEXT *sysContext;
    TSS2_ABI_VERSION tstAbiVersion = { TSSWG_INTEROP, TSS_SAPI_FIRST_FAMILY, TSS_SAPI_FIRST_LEVEL, TSS_SAPI_FIRST_VERSION };

    DebugPrintf( NO_PREFIX, "\nABI NEGOTIATION TESTS:\n" );

    // Get the size needed for system context structure.
    contextSize = Tss2_Sys_GetContextSize( contextSize );

    // Allocate the space for the system context structure.
    sysContext = (TSS2_SYS_CONTEXT *)malloc( contextSize );

    if( sysContext != 0 )
    {
        // Initialized the system context structure.
        tstAbiVersion.tssCreator = 0xF0000000;
        rval = Tss2_Sys_Initialize( sysContext, contextSize, resMgrTctiContext, &tstAbiVersion );
        CheckFailed( rval, TSS2_SYS_RC_ABI_MISMATCH );

        tstAbiVersion.tssCreator = TSSWG_INTEROP;
        tstAbiVersion.tssFamily = 0xF0000000;
        rval = Tss2_Sys_Initialize( sysContext, contextSize, resMgrTctiContext, &tstAbiVersion );
        CheckFailed( rval, TSS2_SYS_RC_ABI_MISMATCH );

        tstAbiVersion.tssFamily = TSS_SAPI_FIRST_FAMILY;
        tstAbiVersion.tssLevel = 0xF0000000;
        rval = Tss2_Sys_Initialize( sysContext, contextSize, resMgrTctiContext, &tstAbiVersion );
        CheckFailed( rval, TSS2_SYS_RC_ABI_MISMATCH );

        tstAbiVersion.tssLevel = TSS_SAPI_FIRST_LEVEL;
        tstAbiVersion.tssVersion = 0xF0000000;
        rval = Tss2_Sys_Initialize( sysContext, contextSize, resMgrTctiContext, &tstAbiVersion );
        CheckFailed( rval, TSS2_SYS_RC_ABI_MISMATCH );
    }
    free( sysContext );
}


#ifdef __cplusplus
extern "C" {
#endif

extern int dummy_test();

#ifdef __cplusplus
}
#endif

extern TSS2_RC SocketSendTpmCommand(
    TSS2_TCTI_CONTEXT *tctiContext,       /* in */
    size_t             command_size,      /* in */
    uint8_t           *command_buffer     /* in */
    );

TSS2_RC SocketReceiveTpmResponse(
    TSS2_TCTI_CONTEXT *tctiContext,     /* in */
    size_t          *response_size,     /* out */
    unsigned char   *response_buffer,    /* in */
    int32_t         timeout
    );

void TestCreate1()
{
    UINT32 rval;
    TPM2B_SENSITIVE_CREATE  inSensitive = { { sizeof( TPM2B_SENSITIVE_CREATE ) - 2, } };
    TPM2B_PUBLIC            inPublic = { { sizeof( TPM2B_PUBLIC ) - 2, } };
    TPM2B_DATA              outsideInfo = { { sizeof( TPM2B_DATA ) - 2, } };
    TPML_PCR_SELECTION      creationPCR;

    TPMS_AUTH_COMMAND sessionData = { TPM_RS_PW, };
    TPMS_AUTH_RESPONSE sessionDataOut;
    TPMS_AUTH_COMMAND *sessionDataArray[1] = { &sessionData };
    TPMS_AUTH_RESPONSE *sessionDataOutArray[1] = { &sessionDataOut };
    TSS2_SYS_CMD_AUTHS sessionsData = { 1, &sessionDataArray[0] };
    TSS2_SYS_RSP_AUTHS sessionsDataOut = { 1, &sessionDataOutArray[0] };

    TPM2B_NAME name = { { sizeof( TPM2B_NAME ) - 2, } };
    TPM2B_PUBLIC outPublic = { { sizeof( TPM2B_PUBLIC ) - 2, } };
    TPM2B_CREATION_DATA creationData =  { { sizeof( TPM2B_CREATION_DATA ) - 2, } };
    TPM2B_DIGEST creationHash = { { sizeof( TPM2B_DIGEST ) - 2, } };
    TPMT_TK_CREATION creationTicket = { 0, 0, { { sizeof( TPM2B_DIGEST ) - 2, } } };

    sessionDataArray[0] = &sessionData;
    sessionDataOutArray[0] = &sessionDataOut;

    sessionsDataOut.rspAuths = &sessionDataOutArray[0];
    sessionsData.cmdAuths = &sessionDataArray[0];

    sessionsDataOut.rspAuthsCount = 1;

    printf( "\nCREATE PRIMARY, encrypt and decrypt TESTS:\n" );

    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.userAuth = loadedSha1KeyAuth;
    inSensitive.t.sensitive.data.t.size = 0;
    inSensitive.t.size = loadedSha1KeyAuth.b.size + 2;

    inPublic.t.publicArea.type = TPM_ALG_RSA;
    inPublic.t.publicArea.nameAlg = TPM_ALG_SHA1;

    // First clear attributes bit field.
    *(UINT32 *)&( inPublic.t.publicArea.objectAttributes) = 0;
    inPublic.t.publicArea.objectAttributes.restricted = 1;
    inPublic.t.publicArea.objectAttributes.userWithAuth = 1;
    inPublic.t.publicArea.objectAttributes.decrypt = 1;
    inPublic.t.publicArea.objectAttributes.fixedTPM = 1;
    inPublic.t.publicArea.objectAttributes.fixedParent = 1;
    inPublic.t.publicArea.objectAttributes.sensitiveDataOrigin = 1;

    inPublic.t.publicArea.authPolicy.t.size = 0;

    inPublic.t.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
    inPublic.t.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_ECB;
    inPublic.t.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 1024;
    inPublic.t.publicArea.parameters.rsaDetail.exponent = 0;

    inPublic.t.publicArea.unique.rsa.t.size = 0;

    outsideInfo.t.size = 0;
    creationPCR.count = 0;

    sessionData.sessionHandle = TPM_RS_PW;

    // Init nonce.
    sessionData.nonce.t.size = 0;

    // init hmac
    sessionData.hmac.t.size = 0;

    // Init session attributes
    *( (UINT8 *)((void *)&sessionData.sessionAttributes ) ) = 0;

    sessionsData.cmdAuthsCount = 1;
    sessionsData.cmdAuths[0] = &sessionData;

    inPublic.t.publicArea.parameters.rsaDetail.keyBits = 2048;

    // Do SAPI test for non-zero sized outPublic
    outPublic.t.size = 0xff;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_OWNER, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &handle2048rsa, &outPublic, &creationData, &creationHash,
            &creationTicket, &name, &sessionsDataOut );
    CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE );

    outPublic.t.size = 0;
    creationData.t.size = 0;
    INIT_SIMPLE_TPM2B_SIZE( creationHash );
    INIT_SIMPLE_TPM2B_SIZE( name );
    rval = Tss2_Sys_CreatePrimary( sysContext, TPM_RH_OWNER, &sessionsData, &inSensitive, &inPublic,
            &outsideInfo, &creationPCR, &handle2048rsa, &outPublic, &creationData, &creationHash,
            &creationTicket, &name, &sessionsDataOut );
    CheckPassed( rval );

    printf( "\nNew key successfully created in owner hierarchy (RSA 2048).  Handle: 0x%8.8x\n",
            handle2048rsa );
    printf( "Name of created primary key: " );
    PrintSizedBuffer( (TPM2B *)&name );

    char buffer1contents[] = "test";
    //char buffer2contents[] = "string";

    TPMI_DH_OBJECT keyHandle = handle2048rsa;
    TPMT_RSA_DECRYPT inScheme;
    TPM2B_PUBLIC_KEY_RSA message;
    TPM2B_PUBLIC_KEY_RSA outData;

    message.t.size = strlen(buffer1contents);
    memcpy(message.t.buffer, buffer1contents, message.t.size);

    inScheme.scheme = TPM_ALG_NULL;

    //printf("keyHandle: %x\n", keyHandle);
    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_RSA_Encrypt(sysContext, keyHandle, &sessionsData, &message, &inScheme, &outsideInfo, &outData, &sessionsDataOut);
    if( tpmSpecVersion >= 124 ) {
        CheckFailed( rval, TPM_RC_S + TPM_RC_1 + TPM_RC_HANDLE );
    } else {
        CheckFailed( rval, TPM_RC_1 + TPM_RC_HANDLE );
    }

    INIT_SIMPLE_TPM2B_SIZE( outData );
    rval = Tss2_Sys_RSA_Encrypt(sysContext, keyHandle, 0, &message, &inScheme, &outsideInfo, &outData, &sessionsDataOut);
    CheckPassed( rval );

    for (int i=0; i<message.t.size; i++)
    	printf("\nlabel size:%d, label buffer:%x, outData size:%d, outData buffer:%x, msg size:%d, msg buffer:%x", outsideInfo.t.size, outsideInfo.t.buffer[i], outData.t.size, outData.t.buffer[i], message.t.size, message.t.buffer[i]);
    CheckPassed(rval);
}

int
test_invoke (TSS2_SYS_CONTEXT *sapi_context)
{
    TSS2_RC rval = TSS2_RC_SUCCESS;

    sysContext = sapi_context;
    rval = Tss2_Sys_GetTctiContext (sapi_context, &resMgrTctiContext);
    if (rval != TSS2_RC_SUCCESS) {
        printf ("Failed to get TCTI context from sapi_context: 0x%" PRIx32
                "\n", rval);
        return 1;
    }

    nullSessionsDataOut.rspAuthsCount = 1;
    nullSessionsDataOut.rspAuths[0]->nonce = nullSessionNonceOut;
    nullSessionsDataOut.rspAuths[0]->hmac = nullSessionHmac;
    nullSessionNonceOut.t.size = 0;
    nullSessionNonce.t.size = 0;

    loadedSha1KeyAuth.t.size = 2;
    loadedSha1KeyAuth.t.buffer[0] = 0x00;
    loadedSha1KeyAuth.t.buffer[1] = 0xff;

    rval = PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );
    CheckPassed( rval );

    InitEntities();

    InitNullSession( &nullSessionData);

    AbiVersionTests();

    SysInitializeTests();

    SysFinalizeTests();

    GetContextSizeTests();

    GetTctiContextTests();

    GetSetDecryptParamTests();

#ifdef _WIN32
    // This test can only be run agains the simulator
    RmZeroSizedResponseTest();
#endif

    TestTpmStartup();

    // Run this directly after Startup tests to test for
    // a resource mgr corner case with SaveContext.
    TestStartAuthSession();

    GetTpmVersion();

    GetTpmManufacturer();

#ifdef SKIP_CMD_RSP_AUTH_TEST
    printf("** Skipping cmd rsp auth tests\n");
#else
    CmdRspAuthsTests();
#endif

    PrepareTests();

    // Clear DA lockout.
    TestDictionaryAttackLockReset();

    TestDictionaryAttackLockReset();

    TestCreate();
    rval = Tss2_Sys_FlushContext( sysContext, loadedSha1KeyHandle );
    CheckPassed( rval );
    HmacSessionTest();
    TestTpmClear ();
    TestCreate();

#ifdef SKIP_TEST_CREATE1_TEST
    printf("** Skipping TestCreate1()\n");
#else
    TestCreate1();
#endif // SKIP_TEST_CREATE1_TEST

    TestSapiApis();

    TestHierarchyControl();

    NvIndexProto();

    GetSetEncryptParamTests();

    TestEncryptDecryptSession();
    SimpleHmacOrPolicyTest( true );
#ifdef SKIP_SIMPLE_HMAC_OR_POLCY_FALSE_TEST
    printf("** Skipping SimpleHmacOrPolicyTest(false)\n");
#else
    SimpleHmacOrPolicyTest( false );
#endif //SKIP_SIMPLE_HMAC_OR_POLCY_FALSE_TEST

    TestTpmGetCapability();

    TestPcrExtend();
#ifdef SKIP_HASH_TEST
    printf("** Skpping hash test\n");
#else
    TestHash();
#endif

    TestPolicy();
    TestTpmClear();
    TestChangeEps();
    TestChangePps();
    TestHierarchyChangeAuth();
    TestShutdown();
    TestNV();
    TestCreate();
#ifdef SKIP_EVICT_TEST
    printf("** Skipping TestEvict()\n");
#else
    TestEvict();
#endif
    NvIndexProto();
    PasswordTest();
    TestQuote();
    TestDictionaryAttackLockReset();
    TestPcrAllocate();
    TestUnseal();
#ifdef SKIP_RM_TEST
    printf("** Skipping TestRM()\n");
#else
    TestRM();
#endif
    EcEphemeralTest();
    // Clear out RM entries for objects.
    rval = Tss2_Sys_FlushContext( sysContext, handle2048rsa );
    CheckPassed( rval );
    rval = Tss2_Sys_FlushContext( sysContext, loadedSha1KeyHandle );
    CheckPassed( rval );

    PlatformCommand( resMgrTctiContext, MS_SIM_POWER_OFF );

    return 0;
}
