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

#include "InternalRoutines.h"
#include "PolicyAuthorize_fp.h"
#include "Policy_spt_fp.h"
//
//
//     Error Returns                     Meaning
//
//     TPM_RC_HASH                       hash algorithm in keyName is not supported
//     TPM_RC_SIZE                       keyName is not the correct size for its hash algorithm
//     TPM_RC_VALUE                      the current policyDigest of policySession does not match
//                                       approvedPolicy; or checkTicket doesn't match the provided values
//
TPM_RC
TPM2_PolicyAuthorize(
   PolicyAuthorize_In    *in                   // IN: input parameter list
   )
{
   SESSION                     *session;
   TPM2B_DIGEST                 authHash;
   HASH_STATE                   hashState;
   TPMT_TK_VERIFIED             ticket;
   TPM_ALG_ID                   hashAlg;
   UINT16                       digestSize;

// Input Validation

   // Get pointer to the session structure
   session = SessionGet(in->policySession);

   // Extract from the Name of the key, the algorithm used to compute it's Name
   hashAlg = BYTE_ARRAY_TO_UINT16(in->keySign.t.buffer);

   // 'keySign' parameter needs to use a supported hash algorithm, otherwise
   // can't tell how large the digest should be
   digestSize = CryptGetHashDigestSize(hashAlg);
   if(digestSize == 0)
       return TPM_RC_HASH + RC_PolicyAuthorize_keySign;

   if(digestSize != (in->keySign.t.size - 2))
       return TPM_RC_SIZE + RC_PolicyAuthorize_keySign;

   //If this is a trial policy, skip all validations
   if(session->attributes.isTrialPolicy == CLEAR)
   {
       // Check that "approvedPolicy" matches the current value of the
       // policyDigest in policy session
       if(!Memory2BEqual(&session->u2.policyDigest.b,
                         &in->approvedPolicy.b))
           return TPM_RC_VALUE + RC_PolicyAuthorize_approvedPolicy;

         // Validate ticket TPMT_TK_VERIFIED
         // Compute aHash. The authorizing object sign a digest
         // aHash := hash(approvedPolicy || policyRef).
         // Start hash
         authHash.t.size = CryptStartHash(hashAlg, &hashState);

         // add approvedPolicy
         CryptUpdateDigest2B(&hashState, &in->approvedPolicy.b);

      // add policyRef
      CryptUpdateDigest2B(&hashState, &in->policyRef.b);

      // complete hash
      CryptCompleteHash2B(&hashState, &authHash.b);

      // re-compute TPMT_TK_VERIFIED
      TicketComputeVerified(in->checkTicket.hierarchy, &authHash,
                            &in->keySign, &ticket);

      // Compare ticket digest. If not match, return error
      if(!Memory2BEqual(&in->checkTicket.digest.b, &ticket.digest.b))
          return TPM_RC_VALUE+ RC_PolicyAuthorize_checkTicket;
  }

// Internal Data Update

  // Set policyDigest to zero digest
  MemorySet(session->u2.policyDigest.t.buffer, 0,
            session->u2.policyDigest.t.size);

  // Update policyDigest
  PolicyContextUpdate(TPM_CC_PolicyAuthorize, &in->keySign, &in->policyRef,
                      NULL, 0, session);

  return TPM_RC_SUCCESS;

}
