// 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.name);

   // '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;

}