// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014

#include   "InternalRoutines.h"
#include   "Policy_spt_fp.h"
#include   "PolicySigned_fp.h"
#include   "PolicySecret_fp.h"
#include   "PolicyTicket_fp.h"
//
//
//           PolicyParameterChecks()
//
//      This function validates the common parameters of TPM2_PolicySiged() and TPM2_PolicySecret(). The
//      common parameters are nonceTPM, expiration, and cpHashA.
//
TPM_RC
PolicyParameterChecks(
     SESSION          *session,
     UINT64            authTimeout,
     TPM2B_DIGEST     *cpHashA,
     TPM2B_NONCE      *nonce,
     TPM_RC            nonceParameterNumber,
     TPM_RC            cpHashParameterNumber,
     TPM_RC            expirationParameterNumber
     )
{
     TPM_RC            result;
     // Validate that input nonceTPM is correct if present
     if(nonce != NULL && nonce->t.size != 0)
//
   {
         if(!Memory2BEqual(&nonce->b, &session->nonceTPM.b))
             return TPM_RC_NONCE + RC_PolicySigned_nonceTPM;
   }
   // If authTimeout is set (expiration != 0...
   if(authTimeout != 0)
   {
       // ...then nonce must be present
       // nonce present isn't checked in PolicyTicket
       if(nonce != NULL && nonce->t.size == 0)
           // This error says that the time has expired but it is pointing
           // at the nonceTPM value.
           return TPM_RC_EXPIRED + nonceParameterNumber;
         // Validate input expiration.
         // Cannot compare time if clock stop advancing. A TPM_RC_NV_UNAVAILABLE
         // or TPM_RC_NV_RATE error may be returned here.
         result = NvIsAvailable();
         if(result != TPM_RC_SUCCESS)
             return result;
         if(authTimeout < go.clock)
             return TPM_RC_EXPIRED + expirationParameterNumber;
   }
   // If the cpHash is present, then check it
   if(cpHashA != NULL && cpHashA->t.size != 0)
   {
       // The cpHash input has to have the correct size
       if(cpHashA->t.size != session->u2.policyDigest.t.size)
           return TPM_RC_SIZE + cpHashParameterNumber;
         // If the cpHash has already been set, then this input value
         // must match the current value.
         if(     session->u1.cpHash.b.size != 0
             && !Memory2BEqual(&cpHashA->b, &session->u1.cpHash.b))
                 return TPM_RC_CPHASH;
   }
   return TPM_RC_SUCCESS;
}
//
//
//          PolicyContextUpdate()
//
//     Update policy hash Update the policyDigest in policy session by extending policyRef and objectName to
//     it. This will also update the cpHash if it is present.
//
void
PolicyContextUpdate(
   TPM_CC              commandCode,     //   IN:   command code
   TPM2B_NAME         *name,            //   IN:   name of entity
   TPM2B_NONCE        *ref,             //   IN:   the reference data
   TPM2B_DIGEST       *cpHash,          //   IN:   the cpHash (optional)
   UINT64              policyTimeout,
   SESSION            *session          // IN/OUT: policy session to be updated
   )
{
   HASH_STATE               hashState;
   UINT16                   policyDigestSize;
   // Start hash
   policyDigestSize = CryptStartHash(session->authHashAlg, &hashState);
   // policyDigest size should always be the digest size of session hash algorithm.
   pAssert(session->u2.policyDigest.t.size == policyDigestSize);
     // add old digest
     CryptUpdateDigest2B(&hashState, &session->u2.policyDigest.b);
     // add commandCode
     CryptUpdateDigestInt(&hashState, sizeof(commandCode), &commandCode);
     // add name if applicable
     if(name != NULL)
         CryptUpdateDigest2B(&hashState, &name->b);
     // Complete the digest and get the results
     CryptCompleteHash2B(&hashState, &session->u2.policyDigest.b);
     // Start second hash computation
     CryptStartHash(session->authHashAlg, &hashState);
     // add policyDigest
     CryptUpdateDigest2B(&hashState, &session->u2.policyDigest.b);
     // add policyRef
     if(ref != NULL)
         CryptUpdateDigest2B(&hashState, &ref->b);
     // Complete second digest
     CryptCompleteHash2B(&hashState, &session->u2.policyDigest.b);
     // Deal with the cpHash. If the cpHash value is present
     // then it would have already been checked to make sure that
     // it is compatible with the current value so all we need
     // to do here is copy it and set the iscoHashDefined attribute
     if(cpHash != NULL && cpHash->t.size != 0)
     {
         session->u1.cpHash = *cpHash;
         session->attributes.iscpHashDefined = SET;
     }
     // update the timeout if it is specified
     if(policyTimeout!= 0)
     {
     // If the timeout has not been set, then set it to the new value
         if(session->timeOut == 0)
             session->timeOut = policyTimeout;
         else if(session->timeOut > policyTimeout)
             session->timeOut = policyTimeout;
     }
     return;
}