Home | History | Annotate | Download | only in tpm2
      1 // This file was extracted from the TCG Published
      2 // Trusted Platform Module Library
      3 // Part 4: Supporting Routines
      4 // Family "2.0"
      5 // Level 00 Revision 01.16
      6 // October 30, 2014
      7 
      8 #define SESSION_PROCESS_C
      9 #include "InternalRoutines.h"
     10 #include "SessionProcess_fp.h"
     11 #include "Platform.h"
     12 //
     13 //
     14 //          Authorization Support Functions
     15 //
     16 //           IsDAExempted()
     17 //
     18 //     This function indicates if a handle is exempted from DA logic. A handle is exempted if it is
     19 //     a) a primary seed handle,
     20 //     b) an object with noDA bit SET,
     21 //     c) an NV Index with TPMA_NV_NO_DA bit SET, or
     22 //     d) a PCR handle.
     23 //
     24 //     Return Value                      Meaning
     25 //
     26 //     TRUE                              handle is exempted from DA logic
     27 //     FALSE                             handle is not exempted from DA logic
     28 //
     29 BOOL
     30 IsDAExempted(
     31      TPM_HANDLE          handle              // IN: entity handle
     32      )
     33 {
     34      BOOL          result = FALSE;
     35      switch(HandleGetType(handle))
     36      {
     37          case TPM_HT_PERMANENT:
     38              // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
     39              // DA protection.
     40              result = (handle != TPM_RH_LOCKOUT);
     41              break;
     42          // When this function is called, a persistent object will have been loaded
     43          // into an object slot and assigned a transient handle.
     44          case TPM_HT_TRANSIENT:
     45          {
     46              OBJECT      *object;
     47              object = ObjectGet(handle);
     48              result = (object->publicArea.objectAttributes.noDA == SET);
     49              break;
     50          }
     51          case TPM_HT_NV_INDEX:
     52          {
     53              NV_INDEX        nvIndex;
     54                 NvGetIndexInfo(handle, &nvIndex);
     55                 result = (nvIndex.publicArea.attributes.TPMA_NV_NO_DA == SET);
     56                 break;
     57          }
     58          case TPM_HT_PCR:
     59              // PCRs are always exempted from DA.
     60              result = TRUE;
     61              break;
     62          default:
     63              break;
     64    }
     65    return result;
     66 }
     67 //
     68 //
     69 //          IncrementLockout()
     70 //
     71 //     This function is called after an authorization failure that involves use of an authValue. If the entity
     72 //     referenced by the handle is not exempt from DA protection, then the failedTries counter will be
     73 //     incremented.
     74 //
     75 //     Error Returns                  Meaning
     76 //
     77 //     TPM_RC_AUTH_FAIL               authorization failure that caused DA lockout to increment
     78 //     TPM_RC_BAD_AUTH                authorization failure did not cause DA lockout to increment
     79 //
     80 static TPM_RC
     81 IncrementLockout(
     82    UINT32                sessionIndex
     83    )
     84 {
     85    TPM_HANDLE            handle = s_associatedHandles[sessionIndex];
     86    TPM_HANDLE            sessionHandle = s_sessionHandles[sessionIndex];
     87    TPM_RC                result;
     88    SESSION              *session = NULL;
     89    // Don't increment lockout unless the handle associated with the session
     90    // is DA protected or the session is bound to a DA protected entity.
     91    if(sessionHandle == TPM_RS_PW)
     92    {
     93        if(IsDAExempted(handle))
     94            return TPM_RC_BAD_AUTH;
     95    }
     96    else
     97    {
     98        session = SessionGet(sessionHandle);
     99        // If the session is bound to lockout, then use that as the relevant
    100        // handle. This means that an auth failure with a bound session
    101        // bound to lockoutAuth will take precedence over any other
    102        // lockout check
    103        if(session->attributes.isLockoutBound == SET)
    104            handle = TPM_RH_LOCKOUT;
    105          if(      session->attributes.isDaBound == CLEAR
    106                && IsDAExempted(handle)
    107            )
    108                // If the handle was changed to TPM_RH_LOCKOUT, this will not return
    109                // TPM_RC_BAD_AUTH
    110                 return TPM_RC_BAD_AUTH;
    111    }
    112    if(handle == TPM_RH_LOCKOUT)
    113     {
    114          pAssert(gp.lockOutAuthEnabled);
    115          gp.lockOutAuthEnabled = FALSE;
    116          // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
    117          // the lockout auth will be reset at startup.
    118          if(gp.lockoutRecovery != 0)
    119          {
    120              result = NvIsAvailable();
    121              if(result != TPM_RC_SUCCESS)
    122              {
    123                  // No NV access for now. Put the TPM in pending mode.
    124                  s_DAPendingOnNV = TRUE;
    125              }
    126              else
    127              {
    128                  // Update NV.
    129                  NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled);
    130                  g_updateNV = TRUE;
    131              }
    132          }
    133     }
    134     else
    135     {
    136         if(gp.recoveryTime != 0)
    137         {
    138             gp.failedTries++;
    139             result = NvIsAvailable();
    140             if(result != TPM_RC_SUCCESS)
    141             {
    142                 // No NV access for now. Put the TPM in pending mode.
    143                 s_DAPendingOnNV = TRUE;
    144             }
    145             else
    146             {
    147                 // Record changes to NV.
    148                 NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
    149                 g_updateNV = TRUE;
    150             }
    151         }
    152     }
    153     // Register a DA failure and reset the timers.
    154     DARegisterFailure(handle);
    155     return TPM_RC_AUTH_FAIL;
    156 }
    157 //
    158 //
    159 //           IsSessionBindEntity()
    160 //
    161 //      This function indicates if the entity associated with the handle is the entity, to which this session is bound.
    162 //      The binding would occur by making the bind parameter in TPM2_StartAuthSession() not equal to
    163 //      TPM_RH_NULL. The binding only occurs if the session is an HMAC session. The bind value is a
    164 //      combination of the Name and the authValue of the entity.
    165 //
    166 //      Return Value                      Meaning
    167 //
    168 //      TRUE                              handle points to the session start entity
    169 //      FALSE                             handle does not point to the session start entity
    170 //
    171 static BOOL
    172 IsSessionBindEntity(
    173     TPM_HANDLE           associatedHandle,         // IN: handle to be authorized
    174     SESSION             *session                   // IN: associated session
    175     )
    176 {
    177     TPM2B_NAME        entity;                    // The bind value for the entity
    178     // If the session is not bound, return FALSE.
    179     if(!session->attributes.isBound)
    180         return FALSE;
    181     // Compute the bind value for the entity.
    182     SessionComputeBoundEntity(associatedHandle, &entity);
    183     // Compare to the bind value in the session.
    184     session->attributes.requestWasBound =
    185             Memory2BEqual(&entity.b, &session->u1.boundEntity.b);
    186     return session->attributes.requestWasBound;
    187 }
    188 //
    189 //
    190 //           IsPolicySessionRequired()
    191 //
    192 //      Checks if a policy session is required for a command. If a command requires DUP or ADMIN role
    193 //      authorization, then the handle that requires that role is the first handle in the command. This simplifies
    194 //      this checking. If a new command is created that requires multiple ADMIN role authorizations, then it will
    195 //      have to be special-cased in this function. A policy session is required if:
    196 //      a) the command requires the DUP role,
    197 //      b) the command requires the ADMIN role and the authorized entity is an object and its adminWithPolicy
    198 //         bit is SET, or
    199 //      c) the command requires the ADMIN role and the authorized entity is a permanent handle or an NV
    200 //         Index.
    201 //      d) The authorized entity is a PCR belonging to a policy group, and has its policy initialized
    202 //
    203 //      Return Value                     Meaning
    204 //
    205 //      TRUE                             policy session is required
    206 //      FALSE                            policy session is not required
    207 //
    208 static BOOL
    209 IsPolicySessionRequired(
    210     TPM_CC               commandCode,        // IN: command code
    211     UINT32               sessionIndex        // IN: session index
    212     )
    213 {
    214     AUTH_ROLE           role = CommandAuthRole(commandCode, sessionIndex);
    215     TPM_HT              type = HandleGetType(s_associatedHandles[sessionIndex]);
    216     if(role == AUTH_DUP)
    217         return TRUE;
    218     if(role == AUTH_ADMIN)
    219     {
    220         if(type == TPM_HT_TRANSIENT)
    221         {
    222             OBJECT      *object = ObjectGet(s_associatedHandles[sessionIndex]);
    223               if(object->publicArea.objectAttributes.adminWithPolicy == CLEAR)
    224                   return FALSE;
    225          }
    226          return TRUE;
    227     }
    228 //
    229     if(type == TPM_HT_PCR)
    230     {
    231         if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex]))
    232         {
    233             TPM2B_DIGEST        policy;
    234             TPMI_ALG_HASH       policyAlg;
    235             policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex],
    236                                           &policy);
    237             if(policyAlg != TPM_ALG_NULL)
    238                 return TRUE;
    239         }
    240     }
    241     return FALSE;
    242 }
    243 //
    244 //
    245 //           IsAuthValueAvailable()
    246 //
    247 //      This function indicates if authValue is available and allowed for USER role authorization of an entity.
    248 //      This function is similar to IsAuthPolicyAvailable() except that it does not check the size of the authValue
    249 //      as IsAuthPolicyAvailable() does (a null authValue is a valid auth, but a null policy is not a valid policy).
    250 //      This function does not check that the handle reference is valid or if the entity is in an enabled hierarchy.
    251 //      Those checks are assumed to have been performed during the handle unmarshaling.
    252 //
    253 //      Return Value                      Meaning
    254 //
    255 //      TRUE                              authValue is available
    256 //      FALSE                             authValue is not available
    257 //
    258 static BOOL
    259 IsAuthValueAvailable(
    260     TPM_HANDLE           handle,             // IN: handle of entity
    261     TPM_CC               commandCode,        // IN: commandCode
    262     UINT32               sessionIndex        // IN: session index
    263     )
    264 {
    265     BOOL             result = FALSE;
    266     // If a policy session is required, the entity can not be authorized by
    267     // authValue. However, at this point, the policy session requirement should
    268     // already have been checked.
    269     pAssert(!IsPolicySessionRequired(commandCode, sessionIndex));
    270    switch(HandleGetType(handle))
    271    {
    272        case TPM_HT_PERMANENT:
    273            switch(handle)
    274            {
    275                    // At this point hierarchy availability has already been
    276                    // checked so primary seed handles are always available here
    277                case TPM_RH_OWNER:
    278                case TPM_RH_ENDORSEMENT:
    279                case TPM_RH_PLATFORM:
    280 #ifdef VENDOR_PERMANENT
    281                    // This vendor defined handle associated with the
    282                    // manufacturer's shared secret
    283                case VENDOR_PERMANENT:
    284 #endif
    285                    // NullAuth is always available.
    286                case TPM_RH_NULL:
    287                     // At the point when authValue availability is checked, control
    288                    // path has already passed the DA check so LockOut auth is
    289                    // always available here
    290                case TPM_RH_LOCKOUT:
    291                       result = TRUE;
    292                       break;
    293                   default:
    294                       // Otherwise authValue is not available.
    295                       break;
    296             }
    297             break;
    298         case TPM_HT_TRANSIENT:
    299             // A persistent object has already been loaded and the internal
    300             // handle changed.
    301             {
    302                 OBJECT          *object;
    303                 object = ObjectGet(handle);
    304                   // authValue is always available for a sequence object.
    305                   if(ObjectIsSequence(object))
    306                   {
    307                        result = TRUE;
    308                        break;
    309                   }
    310                   // authValue is available for an object if it has its sensitive
    311                   // portion loaded and
    312                   // 1. userWithAuth bit is SET, or
    313                   // 2. ADMIN role is required
    314                   if(    object->attributes.publicOnly == CLEAR
    315                       &&    (object->publicArea.objectAttributes.userWithAuth == SET
    316                          || (CommandAuthRole(commandCode, sessionIndex) == AUTH_ADMIN
    317                             && object->publicArea.objectAttributes.adminWithPolicy
    318                                == CLEAR)))
    319                        result = TRUE;
    320             }
    321             break;
    322         case TPM_HT_NV_INDEX:
    323             // NV Index.
    324             {
    325                 NV_INDEX         nvIndex;
    326                 NvGetIndexInfo(handle, &nvIndex);
    327                 if(IsWriteOperation(commandCode))
    328                 {
    329                     if (nvIndex.publicArea.attributes.TPMA_NV_AUTHWRITE == SET)
    330                          result = TRUE;
    331                   }
    332                   else
    333                   {
    334                       if (nvIndex.publicArea.attributes.TPMA_NV_AUTHREAD == SET)
    335                           result = TRUE;
    336                   }
    337             }
    338             break;
    339         case TPM_HT_PCR:
    340             // PCR handle.
    341             // authValue is always allowed for PCR
    342             result = TRUE;
    343             break;
    344         default:
    345             // Otherwise, authValue is not available
    346             break;
    347    }
    348    return result;
    349 }
    350 //
    351 //
    352 //
    353 //           IsAuthPolicyAvailable()
    354 //
    355 //      This function indicates if an authPolicy is available and allowed.
    356 //      This function does not check that the handle reference is valid or if the entity is in an enabled hierarchy.
    357 //      Those checks are assumed to have been performed during the handle unmarshaling.
    358 //
    359 //      Return Value                      Meaning
    360 //
    361 //      TRUE                              authPolicy is available
    362 //      FALSE                             authPolicy is not available
    363 //
    364 static BOOL
    365 IsAuthPolicyAvailable(
    366     TPM_HANDLE           handle,              // IN: handle of entity
    367     TPM_CC               commandCode,         // IN: commandCode
    368     UINT32               sessionIndex         // IN: session index
    369     )
    370 {
    371     BOOL            result = FALSE;
    372     switch(HandleGetType(handle))
    373     {
    374         case TPM_HT_PERMANENT:
    375             switch(handle)
    376             {
    377                 // At this point hierarchy availability has already been checked.
    378                 case TPM_RH_OWNER:
    379                     if (gp.ownerPolicy.t.size != 0)
    380                         result = TRUE;
    381                     break;
    382                    case TPM_RH_ENDORSEMENT:
    383                        if (gp.endorsementPolicy.t.size != 0)
    384                            result = TRUE;
    385                        break;
    386                    case TPM_RH_PLATFORM:
    387                        if (gc.platformPolicy.t.size != 0)
    388                             result = TRUE;
    389                        break;
    390                    case TPM_RH_LOCKOUT:
    391                        if(gp.lockoutPolicy.t.size != 0)
    392                             result = TRUE;
    393                        break;
    394                    default:
    395                        break;
    396              }
    397              break;
    398          case TPM_HT_TRANSIENT:
    399              {
    400                  // Object handle.
    401                  // An evict object would already have been loaded and given a
    402                  // transient object handle by this point.
    403                  OBJECT *object = ObjectGet(handle);
    404                  // Policy authorization is not available for an object with only
    405                  // public portion loaded.
    406                  if(object->attributes.publicOnly == CLEAR)
    407                  {
    408                      // Policy authorization is always available for an object but
    409                      // is never available for a sequence.
    410                      if(!ObjectIsSequence(object))
    411                          result = TRUE;
    412                  }
    413                  break;
    414              }
    415          case TPM_HT_NV_INDEX:
    416              // An NV Index.
    417              {
    418                   NV_INDEX          nvIndex;
    419                   NvGetIndexInfo(handle, &nvIndex);
    420                   // If the policy size is not zero, check if policy can be used.
    421                   if(nvIndex.publicArea.authPolicy.t.size != 0)
    422                   {
    423                       // If policy session is required for this handle, always
    424                       // uses policy regardless of the attributes bit setting
    425                       if(IsPolicySessionRequired(commandCode, sessionIndex))
    426                            result = TRUE;
    427                       // Otherwise, the presence of the policy depends on the NV
    428                       // attributes.
    429                       else if(IsWriteOperation(commandCode))
    430                       {
    431                            if (   nvIndex.publicArea.attributes.TPMA_NV_POLICYWRITE
    432                                == SET)
    433                                result = TRUE;
    434                       }
    435                       else
    436                       {
    437                            if (    nvIndex.publicArea.attributes.TPMA_NV_POLICYREAD
    438                                == SET)
    439                                result = TRUE;
    440                       }
    441                   }
    442              }
    443              break;
    444          case TPM_HT_PCR:
    445              // PCR handle.
    446              if(PCRPolicyIsAvailable(handle))
    447                   result = TRUE;
    448              break;
    449          default:
    450              break;
    451    }
    452    return result;
    453 }
    454 //
    455 //
    456 //           Session Parsing Functions
    457 //
    458 //           ComputeCpHash()
    459 //
    460 //      This function computes the cpHash as defined in Part 2 and described in Part 1.
    461 //
    462 static void
    463 ComputeCpHash(
    464    TPMI_ALG_HASH        hashAlg,               //   IN: hash algorithm
    465    TPM_CC               commandCode,           //   IN: command code
    466    UINT32               handleNum,             //   IN: number of handle
    467    TPM_HANDLE           handles[],             //   IN: array of handle
    468    UINT32               parmBufferSize,        //   IN: size of input parameter area
    469    BYTE                *parmBuffer,            //   IN: input parameter area
    470    TPM2B_DIGEST        *cpHash,                //   OUT: cpHash
    471    TPM2B_DIGEST        *nameHash               //   OUT: name hash of command
    472    )
    473 {
    474    UINT32               i;
    475    HASH_STATE           hashState;
    476    TPM2B_NAME           name;
    477 //
    478    // cpHash = hash(commandCode [ || authName1
    479    //                           [ || authName2
    480    //                           [ || authName 3 ]]]
    481    //                           [ || parameters])
    482    // A cpHash can contain just a commandCode only if the lone session is
    483    // an audit session.
    484    // Start cpHash.
    485    cpHash->t.size = CryptStartHash(hashAlg, &hashState);
    486    // Add commandCode.
    487    CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
    488    // Add authNames for each of the handles.
    489    for(i = 0; i < handleNum; i++)
    490    {
    491        name.t.size = EntityGetName(handles[i], &name.t.name);
    492        CryptUpdateDigest2B(&hashState, &name.b);
    493    }
    494    // Add the parameters.
    495    CryptUpdateDigest(&hashState, parmBufferSize, parmBuffer);
    496    // Complete the hash.
    497    CryptCompleteHash2B(&hashState, &cpHash->b);
    498    // If the nameHash is needed, compute it here.
    499    if(nameHash != NULL)
    500    {
    501        // Start name hash. hashState may be reused.
    502        nameHash->t.size = CryptStartHash(hashAlg, &hashState);
    503          // Adding names.
    504          for(i = 0; i < handleNum; i++)
    505          {
    506              name.t.size = EntityGetName(handles[i], &name.t.name);
    507              CryptUpdateDigest2B(&hashState, &name.b);
    508          }
    509          // Complete hash.
    510          CryptCompleteHash2B(&hashState, &nameHash->b);
    511    }
    512    return;
    513 }
    514 //
    515 //
    516 //           CheckPWAuthSession()
    517 //
    518 //      This function validates the authorization provided in a PWAP session. It compares the input value to
    519 //      authValue of the authorized entity. Argument sessionIndex is used to get handles handle of the
    520 //      referenced entities from s_inputAuthValues[] and s_associatedHandles[].
    521 //
    522 //      Error Returns                     Meaning
    523 //
    524 //      TPM_RC_AUTH_FAIL                  auth fails and increments DA failure count
    525 //      TPM_RC_BAD_AUTH                   auth fails but DA does not apply
    526 //
    527 static TPM_RC
    528 CheckPWAuthSession(
    529    UINT32              sessionIndex          // IN: index of session to be processed
    530    )
    531 {
    532    TPM2B_AUTH         authValue;
    533    TPM_HANDLE         associatedHandle = s_associatedHandles[sessionIndex];
    534    // Strip trailing zeros from the password.
    535    MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]);
    536    // Get the auth value and size.
    537    authValue.t.size = EntityGetAuthValue(associatedHandle, &authValue.t.buffer);
    538    // Success if the digests are identical.
    539    if(Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &authValue.b))
    540    {
    541        return TPM_RC_SUCCESS;
    542    }
    543    else                    // if the digests are not identical
    544    {
    545        // Invoke DA protection if applicable.
    546        return IncrementLockout(sessionIndex);
    547    }
    548 }
    549 //
    550 //
    551 //          ComputeCommandHMAC()
    552 //
    553 //      This function computes the HMAC for an authorization session in a command.
    554 //
    555 static void
    556 ComputeCommandHMAC(
    557    UINT32              sessionIndex,    // IN: index of session to be processed
    558    TPM2B_DIGEST       *cpHash,          // IN: cpHash
    559    TPM2B_DIGEST       *hmac             // OUT: authorization HMAC
    560    )
    561 {
    562    TPM2B_TYPE(KEY,    (sizeof(AUTH_VALUE) * 2));
    563    TPM2B_KEY           key;
    564    BYTE                marshalBuffer[sizeof(TPMA_SESSION)];
    565    BYTE               *buffer;
    566    INT32               bufferSize;
    567    UINT32              marshalSize;
    568    HMAC_STATE          hmacState;
    569    TPM2B_NONCE        *nonceDecrypt;
    570    TPM2B_NONCE        *nonceEncrypt;
    571    SESSION            *session;
    572    TPM_HT              sessionHandleType =
    573                                HandleGetType(s_sessionHandles[sessionIndex]);
    574    nonceDecrypt = NULL;
    575    nonceEncrypt = NULL;
    576    // Determine if extra nonceTPM values are going to be required.
    577    // If this is the first session (sessionIndex = 0) and it is an authorization
    578    // session that uses an HMAC, then check if additional session nonces are to be
    579    // included.
    580    if(   sessionIndex == 0
    581       && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
    582    {
    583        // If there is a decrypt session and if this is not the decrypt session,
    584        // then an extra nonce may be needed.
    585        if(    s_decryptSessionIndex != UNDEFINED_INDEX
    586            && s_decryptSessionIndex != sessionIndex)
    587        {
    588             // Will add the nonce for the decrypt session.
    589             SESSION *decryptSession
    590                         = SessionGet(s_sessionHandles[s_decryptSessionIndex]);
    591             nonceDecrypt = &decryptSession->nonceTPM;
    592        }
    593        // Now repeat for the encrypt session.
    594        if(    s_encryptSessionIndex != UNDEFINED_INDEX
    595            && s_encryptSessionIndex != sessionIndex
    596 //
    597              && s_encryptSessionIndex != s_decryptSessionIndex)
    598          {
    599              // Have to have the nonce for the encrypt session.
    600              SESSION *encryptSession
    601                          = SessionGet(s_sessionHandles[s_encryptSessionIndex]);
    602              nonceEncrypt = &encryptSession->nonceTPM;
    603          }
    604    }
    605    // Continue with the HMAC processing.
    606    session = SessionGet(s_sessionHandles[sessionIndex]);
    607    // Generate HMAC key.
    608    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
    609    //   Check if the session has an associated handle and if the associated entity
    610    //   is the one to which the session is bound. If not, add the authValue of
    611    //   this entity to the HMAC key.
    612    //   If the session is bound to the object or the session is a policy session
    613    //   with no authValue required, do not include the authValue in the HMAC key.
    614    //   Note: For a policy session, its isBound attribute is CLEARED.
    615    // If the session isn't used for authorization, then there is no auth value
    616    // to add
    617    if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
    618    {
    619        // used for auth so see if this is a policy session with authValue needed
    620        // or an hmac session that is not bound
    621            if (((sessionHandleType == TPM_HT_POLICY_SESSION)
    622                 && (session->attributes.isAuthValueNeeded == SET))
    623                || ((sessionHandleType == TPM_HT_HMAC_SESSION)
    624                    && !IsSessionBindEntity(s_associatedHandles[sessionIndex], session))
    625          )
    626        {
    627            // add the authValue to the HMAC key
    628            pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
    629            key.t.size =   key.t.size
    630                         + EntityGetAuthValue(s_associatedHandles[sessionIndex],
    631                                         (AUTH_VALUE *)&(key.t.buffer[key.t.size]));
    632        }
    633    }
    634     // if the HMAC key size is 0, a NULL string HMAC is allowed
    635     if(    key.t.size == 0
    636         && s_inputAuthValues[sessionIndex].t.size == 0)
    637     {
    638         hmac->t.size = 0;
    639         return;
    640     }
    641    // Start HMAC
    642    hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
    643    // Add cpHash
    644    CryptUpdateDigest2B(&hmacState, &cpHash->b);
    645    // Add nonceCaller
    646    CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
    647    // Add nonceTPM
    648    CryptUpdateDigest2B(&hmacState, &session->nonceTPM.b);
    649    // If needed, add nonceTPM for decrypt session
    650    if(nonceDecrypt != NULL)
    651        CryptUpdateDigest2B(&hmacState, &nonceDecrypt->b);
    652     // If needed, add nonceTPM for encrypt session
    653     if(nonceEncrypt != NULL)
    654         CryptUpdateDigest2B(&hmacState, &nonceEncrypt->b);
    655     // Add sessionAttributes
    656     buffer = marshalBuffer;
    657     bufferSize = sizeof(TPMA_SESSION);
    658     marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]),
    659                                        &buffer, &bufferSize);
    660     CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
    661     // Complete the HMAC computation
    662     CryptCompleteHMAC2B(&hmacState, &hmac->b);
    663     return;
    664 }
    665 //
    666 //
    667 //           CheckSessionHMAC()
    668 //
    669 //      This function checks the HMAC of in a session. It uses ComputeCommandHMAC() to compute the
    670 //      expected HMAC value and then compares the result with the HMAC in the authorization session. The
    671 //      authorization is successful if they are the same.
    672 //      If the authorizations are not the same, IncrementLockout() is called. It will return TPM_RC_AUTH_FAIL if
    673 //      the failure caused the failureCount to increment. Otherwise, it will return TPM_RC_BAD_AUTH.
    674 //
    675 //      Error Returns                    Meaning
    676 //
    677 //      TPM_RC_AUTH_FAIL                 auth failure caused failureCount increment
    678 //      TPM_RC_BAD_AUTH                  auth failure did not cause failureCount increment
    679 //
    680 static TPM_RC
    681 CheckSessionHMAC(
    682     UINT32               sessionIndex,      // IN: index of session to be processed
    683     TPM2B_DIGEST        *cpHash             // IN: cpHash of the command
    684     )
    685 {
    686     TPM2B_DIGEST             hmac;                // authHMAC for comparing
    687     // Compute authHMAC
    688     ComputeCommandHMAC(sessionIndex, cpHash, &hmac);
    689     // Compare the input HMAC with the authHMAC computed above.
    690     if(!Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &hmac.b))
    691     {
    692         // If an HMAC session has a failure, invoke the anti-hammering
    693         // if it applies to the authorized entity or the session.
    694         // Otherwise, just indicate that the authorization is bad.
    695         return IncrementLockout(sessionIndex);
    696     }
    697     return TPM_RC_SUCCESS;
    698 }
    699 //
    700 //
    701 //           CheckPolicyAuthSession()
    702 //
    703 //      This function is used to validate the authorization in a policy session. This function performs the following
    704 //      comparisons to see if a policy authorization is properly provided. The check are:
    705 //      a) compare policyDigest in session with authPolicy associated with the entity to be authorized;
    706 //      b) compare timeout if applicable;
    707 //      c) compare commandCode if applicable;
    708 //
    709 //      d) compare cpHash if applicable; and
    710 //      e) see if PCR values have changed since computed.
    711 //      If all the above checks succeed, the handle is authorized. The order of these comparisons is not
    712 //      important because any failure will result in the same error code.
    713 //
    714 //      Error Returns                     Meaning
    715 //
    716 //      TPM_RC_PCR_CHANGED                PCR value is not current
    717 //      TPM_RC_POLICY_FAIL                policy session fails
    718 //      TPM_RC_LOCALITY                   command locality is not allowed
    719 //      TPM_RC_POLICY_CC                  CC doesn't match
    720 //      TPM_RC_EXPIRED                    policy session has expired
    721 //      TPM_RC_PP                         PP is required but not asserted
    722 //      TPM_RC_NV_UNAVAILABLE             NV is not available for write
    723 //      TPM_RC_NV_RATE                    NV is rate limiting
    724 //
    725 static TPM_RC
    726 CheckPolicyAuthSession(
    727    UINT32              sessionIndex,          //   IN: index of session to be processed
    728    TPM_CC              commandCode,           //   IN: command code
    729    TPM2B_DIGEST       *cpHash,                //   IN: cpHash using the algorithm of this
    730                                               //       session
    731    TPM2B_DIGEST       *nameHash               //   IN: nameHash using the session algorithm
    732    )
    733 {
    734    TPM_RC              result = TPM_RC_SUCCESS;
    735    SESSION            *session;
    736    TPM2B_DIGEST        authPolicy;
    737    TPMI_ALG_HASH       policyAlg;
    738    UINT8               locality;
    739    // Initialize pointer to the auth session.
    740    session = SessionGet(s_sessionHandles[sessionIndex]);
    741    // If the command is TPM_RC_PolicySecret(), make sure that
    742    // either password or authValue is required
    743    if(     commandCode == TPM_CC_PolicySecret
    744        && session->attributes.isPasswordNeeded == CLEAR
    745        && session->attributes.isAuthValueNeeded == CLEAR)
    746        return TPM_RC_MODE;
    747    // See if the PCR counter for the session is still valid.
    748    if( !SessionPCRValueIsCurrent(s_sessionHandles[sessionIndex]) )
    749        return TPM_RC_PCR_CHANGED;
    750    // Get authPolicy.
    751    policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex],
    752                                    &authPolicy);
    753    // Compare authPolicy.
    754    if(!Memory2BEqual(&session->u2.policyDigest.b, &authPolicy.b))
    755        return TPM_RC_POLICY_FAIL;
    756    // Policy is OK so check if the other factors are correct
    757    // Compare policy hash algorithm.
    758    if(policyAlg != session->authHashAlg)
    759        return TPM_RC_POLICY_FAIL;
    760    // Compare timeout.
    761    if(session->timeOut != 0)
    762    {
    763        // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE
    764        // or TPM_RC_NV_RATE error may be returned here.
    765        result = NvIsAvailable();
    766        if(result != TPM_RC_SUCCESS)
    767            return result;
    768         if(session->timeOut < go.clock)
    769             return TPM_RC_EXPIRED;
    770    }
    771    // If command code is provided it must match
    772    if(session->commandCode != 0)
    773    {
    774        if(session->commandCode != commandCode)
    775             return TPM_RC_POLICY_CC;
    776    }
    777    else
    778    {
    779        // If command requires a DUP or ADMIN authorization, the session must have
    780        // command code set.
    781        AUTH_ROLE    role = CommandAuthRole(commandCode, sessionIndex);
    782        if(role == AUTH_ADMIN || role == AUTH_DUP)
    783             return TPM_RC_POLICY_FAIL;
    784    }
    785    // Check command locality.
    786    {
    787        BYTE          sessionLocality[sizeof(TPMA_LOCALITY)];
    788        BYTE         *buffer = sessionLocality;
    789        INT32         bufferSize = sizeof(TPMA_LOCALITY);
    790         // Get existing locality setting in canonical form
    791         TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, &bufferSize);
    792        // See if the locality has been set
    793        if(sessionLocality[0] != 0)
    794        {
    795            // If so, get the current locality
    796            locality = _plat__LocalityGet();
    797            if (locality < 5)
    798            {
    799                if(    ((sessionLocality[0] & (1 << locality)) == 0)
    800                    || sessionLocality[0] > 31)
    801                    return TPM_RC_LOCALITY;
    802            }
    803            else if (locality > 31)
    804            {
    805                if(sessionLocality[0] != locality)
    806                    return TPM_RC_LOCALITY;
    807            }
    808            else
    809            {
    810                // Could throw an assert here but a locality error is just
    811                // as good. It just means that, whatever the locality is, it isn't
    812                // the locality requested so...
    813                return TPM_RC_LOCALITY;
    814            }
    815        }
    816    } // end of locality check
    817    // Check physical presence.
    818    if(   session->attributes.isPPRequired == SET
    819       && !_plat__PhysicalPresenceAsserted())
    820        return TPM_RC_PP;
    821    // Compare cpHash/nameHash if defined, or if the command requires an ADMIN or
    822    // DUP role for this handle.
    823    if(session->u1.cpHash.b.size != 0)
    824    {
    825        if(session->attributes.iscpHashDefined)
    826        {
    827             // Compare cpHash.
    828             if(!Memory2BEqual(&session->u1.cpHash.b, &cpHash->b))
    829                 return TPM_RC_POLICY_FAIL;
    830        }
    831        else
    832        {
    833             // Compare nameHash.
    834             // When cpHash is not defined, nameHash is placed in its space.
    835             if(!Memory2BEqual(&session->u1.cpHash.b, &nameHash->b))
    836                 return TPM_RC_POLICY_FAIL;
    837        }
    838    }
    839    if(session->attributes.checkNvWritten)
    840    {
    841        NV_INDEX         nvIndex;
    842          // If this is not an NV index, the policy makes no sense so fail it.
    843          if(HandleGetType(s_associatedHandles[sessionIndex])!= TPM_HT_NV_INDEX)
    844              return TPM_RC_POLICY_FAIL;
    845          // Get the index data
    846          NvGetIndexInfo(s_associatedHandles[sessionIndex], &nvIndex);
    847          // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
    848          if(    (nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
    849              != (session->attributes.nvWrittenState == SET))
    850              return TPM_RC_POLICY_FAIL;
    851    }
    852    return TPM_RC_SUCCESS;
    853 }
    854 //
    855 //
    856 //           RetrieveSessionData()
    857 //
    858 //      This function will unmarshal the sessions in the session area of a command. The values are placed in the
    859 //      arrays that are defined at the beginning of this file. The normal unmarshaling errors are possible.
    860 //
    861 //      Error Returns                     Meaning
    862 //
    863 //      TPM_RC_SUCCSS                     unmarshaled without error
    864 //      TPM_RC_SIZE                       the number of bytes unmarshaled is not the same as the value for
    865 //                                        authorizationSize in the command
    866 //
    867 static TPM_RC
    868 RetrieveSessionData (
    869    TPM_CC               commandCode,         //   IN: command   code
    870    UINT32              *sessionCount,        //   OUT: number   of sessions found
    871    BYTE                *sessionBuffer,       //   IN: pointer   to the session buffer
    872    INT32                bufferSize           //   IN: size of   the session buffer
    873    )
    874 {
    875    int             sessionIndex;
    876    int             i;
    877    TPM_RC          result;
    878    SESSION        *session;
    879    TPM_HT          sessionType;
    880    s_decryptSessionIndex = UNDEFINED_INDEX;
    881    s_encryptSessionIndex = UNDEFINED_INDEX;
    882    s_auditSessionIndex = UNDEFINED_INDEX;
    883    for(sessionIndex = 0; bufferSize > 0; sessionIndex++)
    884    {
    885        // If maximum allowed number of sessions has been parsed, return a size
    886        // error with a session number that is larger than the number of allowed
    887        // sessions
    888        if(sessionIndex == MAX_SESSION_NUM)
    889            return TPM_RC_SIZE + TPM_RC_S + g_rcIndex[sessionIndex+1];
    890         // make sure that the associated handle for each session starts out
    891         // unassigned
    892         s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
    893         // First parameter: Session handle.
    894         result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
    895                                                 &sessionBuffer, &bufferSize, TRUE);
    896         if(result != TPM_RC_SUCCESS)
    897             return result + TPM_RC_S + g_rcIndex[sessionIndex];
    898         // Second parameter: Nonce.
    899         result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
    900                                        &sessionBuffer, &bufferSize);
    901         if(result != TPM_RC_SUCCESS)
    902             return result + TPM_RC_S + g_rcIndex[sessionIndex];
    903         // Third parameter: sessionAttributes.
    904         result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
    905                                         &sessionBuffer, &bufferSize);
    906         if(result != TPM_RC_SUCCESS)
    907             return result + TPM_RC_S + g_rcIndex[sessionIndex];
    908         // Fourth parameter: authValue (PW or HMAC).
    909         result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
    910                                       &sessionBuffer, &bufferSize);
    911         if(result != TPM_RC_SUCCESS)
    912             return result + TPM_RC_S + g_rcIndex[sessionIndex];
    913         if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
    914         {
    915             // A PWAP session needs additional processing.
    916             //      Can't have any attributes set other than continueSession bit
    917             if(    s_attributes[sessionIndex].encrypt
    918                 || s_attributes[sessionIndex].decrypt
    919                 || s_attributes[sessionIndex].audit
    920                 || s_attributes[sessionIndex].auditExclusive
    921                 || s_attributes[sessionIndex].auditReset
    922               )
    923                  return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    924               //     The nonce size must be zero.
    925               if(s_nonceCaller[sessionIndex].t.size != 0)
    926                   return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex];
    927             continue;
    928         }
    929         // For not password sessions...
    930         // Find out if the session is loaded.
    931         if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
    932             return TPM_RC_REFERENCE_S0 + sessionIndex;
    933         sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
    934         session = SessionGet(s_sessionHandles[sessionIndex]);
    935         // Check if the session is an HMAC/policy session.
    936          if(        (   session->attributes.isPolicy == SET
    937                      && sessionType == TPM_HT_HMAC_SESSION
    938                     )
    939                  || (    session->attributes.isPolicy == CLEAR
    940                       && sessionType == TPM_HT_POLICY_SESSION
    941                     )
    942              )
    943                   return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
    944          // Check that this handle has not previously been used.
    945          for(i = 0; i < sessionIndex; i++)
    946          {
    947              if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
    948                  return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
    949          }
    950          // If the session is used for parameter encryption or audit as well, set
    951          // the corresponding indices.
    952          // First process decrypt.
    953          if(s_attributes[sessionIndex].decrypt)
    954          {
    955              // Check if the commandCode allows command parameter encryption.
    956              if(DecryptSize(commandCode) == 0)
    957                  return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    958                   // Encrypt attribute can only appear in one session
    959                   if(s_decryptSessionIndex != UNDEFINED_INDEX)
    960                       return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    961                   // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
    962                   if(session->symmetric.algorithm == TPM_ALG_NULL)
    963                       return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
    964                   // All checks passed, so set the index for the session used to decrypt
    965                   // a command parameter.
    966                   s_decryptSessionIndex = sessionIndex;
    967          }
    968          // Now process encrypt.
    969          if(s_attributes[sessionIndex].encrypt)
    970          {
    971              // Check if the commandCode allows response parameter encryption.
    972              if(EncryptSize(commandCode) == 0)
    973                  return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    974                   // Encrypt attribute can only appear in one session.
    975                   if(s_encryptSessionIndex != UNDEFINED_INDEX)
    976                       return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    977                   // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
    978                   if(session->symmetric.algorithm == TPM_ALG_NULL)
    979                       return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
    980                   // All checks passed, so set the index for the session used to encrypt
    981                   // a response parameter.
    982                   s_encryptSessionIndex = sessionIndex;
    983          }
    984          // At last process audit.
    985          if(s_attributes[sessionIndex].audit)
    986          {
    987              // Audit attribute can only appear in one session.
    988              if(s_auditSessionIndex != UNDEFINED_INDEX)
    989                  return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    990                // An audit session can not be policy session.
    991                if(    HandleGetType(s_sessionHandles[sessionIndex])
    992                    == TPM_HT_POLICY_SESSION)
    993                     return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
    994                // If this is a reset of the audit session, or the first use
    995                // of the session as an audit session, it doesn't matter what
    996                // the exclusive state is. The session will become exclusive.
    997                if(    s_attributes[sessionIndex].auditReset == CLEAR
    998                    && session->attributes.isAudit == SET)
    999                {
   1000                     // Not first use or reset. If auditExlusive is SET, then this
   1001                     // session must be the current exclusive session.
   1002                     if(    s_attributes[sessionIndex].auditExclusive == SET
   1003                         && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
   1004                         return TPM_RC_EXCLUSIVE;
   1005                }
   1006                s_auditSessionIndex = sessionIndex;
   1007          }
   1008          // Initialize associated handle as undefined. This will be changed when
   1009          // the handles are processed.
   1010          s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
   1011     }
   1012     // Set the number of sessions found.
   1013     *sessionCount = sessionIndex;
   1014     return TPM_RC_SUCCESS;
   1015 }
   1016 //
   1017 //
   1018 //             CheckLockedOut()
   1019 //
   1020 //      This function checks to see if the TPM is in lockout. This function should only be called if the entity being
   1021 //      checked is subject to DA protection. The TPM is in lockout if the NV is not available and a DA write is
   1022 //      pending. Otherwise the TPM is locked out if checking for lockoutAuth (lockoutAuthCheck == TRUE) and
   1023 //      use of lockoutAuth is disabled, or failedTries >= maxTries
   1024 //
   1025 //      Error Returns                    Meaning
   1026 //
   1027 //      TPM_RC_NV_RATE                   NV is rate limiting
   1028 //      TPM_RC_NV_UNAVAILABLE            NV is not available at this time
   1029 //      TPM_RC_LOCKOUT                   TPM is in lockout
   1030 //
   1031 static TPM_RC
   1032 CheckLockedOut(
   1033     BOOL                 lockoutAuthCheck             // IN: TRUE if checking is for lockoutAuth
   1034     )
   1035 {
   1036     TPM_RC         result;
   1037     // If NV is unavailable, and current cycle state recorded in NV is not
   1038     // SHUTDOWN_NONE, refuse to check any authorization because we would
   1039     // not be able to handle a DA failure.
   1040     result = NvIsAvailable();
   1041     if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE)
   1042         return result;
   1043     // Check if DA info needs to be updated in NV.
   1044     if(s_DAPendingOnNV)
   1045     {
   1046          // If NV is accessible, ...
   1047          if(result == TPM_RC_SUCCESS)
   1048          {
   1049               // ... write the pending DA data and proceed.
   1050               NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED,
   1051                               &gp.lockOutAuthEnabled);
   1052               NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
   1053               g_updateNV = TRUE;
   1054               s_DAPendingOnNV = FALSE;
   1055          }
   1056          else
   1057          {
   1058               // Otherwise no authorization can be checked.
   1059               return result;
   1060          }
   1061    }
   1062    // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
   1063    // is disabled...
   1064    if(lockoutAuthCheck)
   1065    {
   1066        if(gp.lockOutAuthEnabled == FALSE)
   1067            return TPM_RC_LOCKOUT;
   1068    }
   1069    else
   1070    {
   1071        // ... or if the number of failed tries has been maxed out.
   1072        if(gp.failedTries >= gp.maxTries)
   1073            return TPM_RC_LOCKOUT;
   1074    }
   1075    return TPM_RC_SUCCESS;
   1076 }
   1077 //
   1078 //
   1079 //           CheckAuthSession()
   1080 //
   1081 //      This function checks that the authorization session properly authorizes the use of the associated handle.
   1082 //
   1083 //      Error Returns                     Meaning
   1084 //
   1085 //      TPM_RC_LOCKOUT                    entity is protected by DA and TPM is in lockout, or TPM is locked out
   1086 //                                        on NV update pending on DA parameters
   1087 //      TPM_RC_PP                         Physical Presence is required but not provided
   1088 //      TPM_RC_AUTH_FAIL                  HMAC or PW authorization failed with DA side-effects (can be a
   1089 //                                        policy session)
   1090 //      TPM_RC_BAD_AUTH                   HMAC or PW authorization failed without DA side-effects (can be a
   1091 //                                        policy session)
   1092 //      TPM_RC_POLICY_FAIL                if policy session fails
   1093 //      TPM_RC_POLICY_CC                  command code of policy was wrong
   1094 //      TPM_RC_EXPIRED                    the policy session has expired
   1095 //      TPM_RC_PCR                        ???
   1096 //      TPM_RC_AUTH_UNAVAILABLE           authValue or authPolicy unavailable
   1097 //
   1098 static TPM_RC
   1099 CheckAuthSession(
   1100    TPM_CC               commandCode,           //   IN:    commandCode
   1101    UINT32               sessionIndex,          //   IN:    index of session to be processed
   1102    TPM2B_DIGEST        *cpHash,                //   IN:    cpHash
   1103    TPM2B_DIGEST        *nameHash               //   IN:    nameHash
   1104 //
   1105    )
   1106 {
   1107    TPM_RC              result;
   1108    SESSION            *session = NULL;
   1109    TPM_HANDLE          sessionHandle = s_sessionHandles[sessionIndex];
   1110    TPM_HANDLE          associatedHandle = s_associatedHandles[sessionIndex];
   1111    TPM_HT              sessionHandleType = HandleGetType(sessionHandle);
   1112    pAssert(sessionHandle != TPM_RH_UNASSIGNED);
   1113    if(sessionHandle != TPM_RS_PW)
   1114        session = SessionGet(sessionHandle);
   1115    pAssert(sessionHandleType != TPM_HT_POLICY_SESSION || session != NULL);
   1116    // If the authorization session is not a policy session, or if the policy
   1117    // session requires authorization, then check lockout.
   1118    if(    sessionHandleType != TPM_HT_POLICY_SESSION
   1119       || session->attributes.isAuthValueNeeded
   1120       || session->attributes.isPasswordNeeded)
   1121    {
   1122        // See if entity is subject to lockout.
   1123        if(!IsDAExempted(associatedHandle))
   1124        {
   1125            // If NV is unavailable, and current cycle state recorded in NV is not
   1126            // SHUTDOWN_NONE, refuse to check any authorization because we would
   1127            // not be able to handle a DA failure.
   1128            result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
   1129            if(result != TPM_RC_SUCCESS)
   1130                return result;
   1131        }
   1132    }
   1133    if(associatedHandle == TPM_RH_PLATFORM)
   1134    {
   1135        // If the physical presence is required for this command, check for PP
   1136        // assertion. If it isn't asserted, no point going any further.
   1137        if(    PhysicalPresenceIsRequired(commandCode)
   1138            && !_plat__PhysicalPresenceAsserted()
   1139          )
   1140             return TPM_RC_PP;
   1141    }
   1142    // If a policy session is required, make sure that it is being used.
   1143    if(   IsPolicySessionRequired(commandCode, sessionIndex)
   1144       && sessionHandleType != TPM_HT_POLICY_SESSION)
   1145        return TPM_RC_AUTH_TYPE;
   1146    // If this is a PW authorization, check it and return.
   1147    if(sessionHandle == TPM_RS_PW)
   1148    {
   1149        if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
   1150             return CheckPWAuthSession(sessionIndex);
   1151        else
   1152             return TPM_RC_AUTH_UNAVAILABLE;
   1153    }
   1154    // If this is a policy session, ...
   1155    if(sessionHandleType == TPM_HT_POLICY_SESSION)
   1156    {
   1157        // ... see if the entity has a policy, ...
   1158        if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex))
   1159             return TPM_RC_AUTH_UNAVAILABLE;
   1160        // ... and check the policy session.
   1161        result = CheckPolicyAuthSession(sessionIndex, commandCode,
   1162                                         cpHash, nameHash);
   1163        if (result != TPM_RC_SUCCESS)
   1164             return result;
   1165    }
   1166    else
   1167    {
   1168        // For non policy, the entity being accessed must allow authorization
   1169        // with an auth value. This is required even if the auth value is not
   1170        // going to be used in an HMAC because it is bound.
   1171        if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
   1172            return TPM_RC_AUTH_UNAVAILABLE;
   1173    }
   1174    // At this point, the session must be either a policy or an HMAC session.
   1175    session = SessionGet(s_sessionHandles[sessionIndex]);
   1176    if(         sessionHandleType == TPM_HT_POLICY_SESSION
   1177          &&    session->attributes.isPasswordNeeded == SET)
   1178    {
   1179          // For policy session that requires a password, check it as PWAP session.
   1180          return CheckPWAuthSession(sessionIndex);
   1181    }
   1182    else
   1183    {
   1184        // For other policy or HMAC sessions, have its HMAC checked.
   1185        return CheckSessionHMAC(sessionIndex, cpHash);
   1186    }
   1187 }
   1188 #ifdef    TPM_CC_GetCommandAuditDigest
   1189 //
   1190 //
   1191 //            CheckCommandAudit()
   1192 //
   1193 //       This function checks if the current command may trigger command audit, and if it is safe to perform the
   1194 //       action.
   1195 //
   1196 //       Error Returns                     Meaning
   1197 //
   1198 //       TPM_RC_NV_UNAVAILABLE             NV is not available for write
   1199 //       TPM_RC_NV_RATE                    NV is rate limiting
   1200 //
   1201 static TPM_RC
   1202 CheckCommandAudit(
   1203    TPM_CC               commandCode,                   //   IN:   Command code
   1204    UINT32               handleNum,                     //   IN:   number of element in handle array
   1205    TPM_HANDLE           handles[],                     //   IN:   array of handle
   1206    BYTE                *parmBufferStart,               //   IN:   start of parameter buffer
   1207    UINT32               parmBufferSize                 //   IN:   size of parameter buffer
   1208    )
   1209 {
   1210    TPM_RC          result = TPM_RC_SUCCESS;
   1211    // If audit is implemented, need to check to see if auditing is being done
   1212    // for this command.
   1213    if(CommandAuditIsRequired(commandCode))
   1214    {
   1215        // If the audit digest is clear and command audit is required, NV must be
   1216        // available so that TPM2_GetCommandAuditDigest() is able to increment
   1217        // audit counter. If NV is not available, the function bails out to prevent
   1218        // the TPM from attempting an operation that would fail anyway.
   1219        if(     gr.commandAuditDigest.t.size == 0
   1220            || commandCode == TPM_CC_GetCommandAuditDigest)
   1221        {
   1222             result = NvIsAvailable();
   1223             if(result != TPM_RC_SUCCESS)
   1224                 return result;
   1225        }
   1226        ComputeCpHash(gp.auditHashAlg, commandCode, handleNum,
   1227                          handles, parmBufferSize, parmBufferStart,
   1228                          &s_cpHashForCommandAudit, NULL);
   1229     }
   1230    return TPM_RC_SUCCESS;
   1231 }
   1232 #endif
   1233 //
   1234 //
   1235 //           ParseSessionBuffer()
   1236 //
   1237 //       This function is the entry function for command session processing. It iterates sessions in session area
   1238 //       and reports if the required authorization has been properly provided. It also processes audit session and
   1239 //       passes the information of encryption sessions to parameter encryption module.
   1240 //
   1241 //       Error Returns                   Meaning
   1242 //
   1243 //       various                         parsing failure or authorization failure
   1244 //
   1245 TPM_RC
   1246 ParseSessionBuffer(
   1247     TPM_CC              commandCode,                    //   IN:   Command code
   1248     UINT32              handleNum,                      //   IN:   number of element in handle array
   1249     TPM_HANDLE          handles[],                      //   IN:   array of handle
   1250     BYTE               *sessionBufferStart,             //   IN:   start of session buffer
   1251     UINT32              sessionBufferSize,              //   IN:   size of session buffer
   1252     BYTE               *parmBufferStart,                //   IN:   start of parameter buffer
   1253     UINT32              parmBufferSize                  //   IN:   size of parameter buffer
   1254     )
   1255 {
   1256     TPM_RC              result;
   1257     UINT32              i;
   1258     INT32               size = 0;
   1259     TPM2B_AUTH          extraKey;
   1260     UINT32              sessionIndex;
   1261     SESSION            *session;
   1262     TPM2B_DIGEST        cpHash;
   1263     TPM2B_DIGEST        nameHash;
   1264     TPM_ALG_ID          cpHashAlg = TPM_ALG_NULL;             // algID for the last computed
   1265                                                               // cpHash
   1266     // Check if a command allows any session in its session area.
   1267     if(!IsSessionAllowed(commandCode))
   1268         return TPM_RC_AUTH_CONTEXT;
   1269     // Default-initialization.
   1270     s_sessionNum = 0;
   1271     cpHash.t.size = 0;
   1272     result = RetrieveSessionData(commandCode, &s_sessionNum,
   1273                                  sessionBufferStart, sessionBufferSize);
   1274     if(result != TPM_RC_SUCCESS)
   1275         return result;
   1276     // There is no command in the TPM spec that has more handles than
   1277     // MAX_SESSION_NUM.
   1278     pAssert(handleNum <= MAX_SESSION_NUM);
   1279     // Associate the session with an authorization handle.
   1280     for(i = 0; i < handleNum; i++)
   1281     {
   1282         if(CommandAuthRole(commandCode, i) != AUTH_NONE)
   1283         {
   1284             // If the received session number is less than the number of handle
   1285             // that requires authorization, an error should be returned.
   1286              // Note: for all the TPM 2.0 commands, handles requiring
   1287              // authorization come first in a command input.
   1288              if(i > (s_sessionNum - 1))
   1289                  return TPM_RC_AUTH_MISSING;
   1290              // Record the handle associated with the authorization session
   1291              s_associatedHandles[i] = handles[i];
   1292          }
   1293    }
   1294    // Consistency checks are done first to avoid auth failure when the command
   1295    // will not be executed anyway.
   1296    for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++)
   1297    {
   1298        // PW session must be an authorization session
   1299        if(s_sessionHandles[sessionIndex] == TPM_RS_PW )
   1300        {
   1301             if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
   1302                 return TPM_RC_HANDLE + g_rcIndex[sessionIndex];
   1303        }
   1304        else
   1305        {
   1306             session = SessionGet(s_sessionHandles[sessionIndex]);
   1307              // A trial session can not appear in session area, because it cannot
   1308              // be used for authorization, audit or encrypt/decrypt.
   1309              if(session->attributes.isTrialPolicy == SET)
   1310                  return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
   1311              // See if the session is bound to a DA protected entity
   1312              // NOTE: Since a policy session is never bound, a policy is still
   1313              // usable even if the object is DA protected and the TPM is in
   1314              // lockout.
   1315              if(session->attributes.isDaBound == SET)
   1316              {
   1317                  result = CheckLockedOut(session->attributes.isLockoutBound == SET);
   1318                  if(result != TPM_RC_SUCCESS)
   1319                      return result;
   1320              }
   1321              // If the current cpHash is the right one, don't re-compute.
   1322              if(cpHashAlg != session->authHashAlg)    // different so compute
   1323              {
   1324                  cpHashAlg = session->authHashAlg;    // save this new algID
   1325                  ComputeCpHash(session->authHashAlg, commandCode, handleNum,
   1326                                handles, parmBufferSize, parmBufferStart,
   1327                                &cpHash, &nameHash);
   1328              }
   1329              // If this session is for auditing, save the cpHash.
   1330              if(s_attributes[sessionIndex].audit)
   1331                  s_cpHashForAudit = cpHash;
   1332          }
   1333          // if the session has an associated handle, check the auth
   1334          if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
   1335          {
   1336               result = CheckAuthSession(commandCode, sessionIndex,
   1337                                         &cpHash, &nameHash);
   1338               if(result != TPM_RC_SUCCESS)
   1339                   return RcSafeAddToResult(result,
   1340                                            TPM_RC_S + g_rcIndex[sessionIndex]);
   1341          }
   1342          else
   1343          {
   1344               // a session that is not for authorization must either be encrypt,
   1345               // decrypt, or audit
   1346               if(     s_attributes[sessionIndex].audit == CLEAR
   1347                    && s_attributes[sessionIndex].encrypt == CLEAR
   1348                    && s_attributes[sessionIndex].decrypt == CLEAR)
   1349                    return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
   1350                // check HMAC for encrypt/decrypt/audit only sessions
   1351                result = CheckSessionHMAC(sessionIndex, &cpHash);
   1352                if(result != TPM_RC_SUCCESS)
   1353                    return RcSafeAddToResult(result,
   1354                                             TPM_RC_S + g_rcIndex[sessionIndex]);
   1355           }
   1356    }
   1357 #ifdef TPM_CC_GetCommandAuditDigest
   1358    // Check if the command should be audited.
   1359    result = CheckCommandAudit(commandCode, handleNum, handles,
   1360                               parmBufferStart, parmBufferSize);
   1361    if(result != TPM_RC_SUCCESS)
   1362        return result;              // No session number to reference
   1363 #endif
   1364    // Decrypt the first parameter if applicable. This should be the last operation
   1365    // in session processing.
   1366    // If the encrypt session is associated with a handle and the handle's
   1367    // authValue is available, then authValue is concatenated with sessionAuth to
   1368    // generate encryption key, no matter if the handle is the session bound entity
   1369    // or not.
   1370    if(s_decryptSessionIndex != UNDEFINED_INDEX)
   1371    {
   1372        // Get size of the leading size field in decrypt parameter
   1373        if(    s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED
   1374            && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex],
   1375                                    commandCode,
   1376                                    s_decryptSessionIndex)
   1377          )
   1378        {
   1379             extraKey.b.size=
   1380                 EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex],
   1381                                    &extraKey.t.buffer);
   1382        }
   1383        else
   1384        {
   1385             extraKey.b.size = 0;
   1386        }
   1387        size = DecryptSize(commandCode);
   1388        result = CryptParameterDecryption(
   1389                      s_sessionHandles[s_decryptSessionIndex],
   1390                      &s_nonceCaller[s_decryptSessionIndex].b,
   1391                      parmBufferSize, (UINT16)size,
   1392                      &extraKey,
   1393                      parmBufferStart);
   1394        if(result != TPM_RC_SUCCESS)
   1395             return RcSafeAddToResult(result,
   1396                                      TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
   1397    }
   1398    return TPM_RC_SUCCESS;
   1399 }
   1400 //
   1401 //
   1402 //              CheckAuthNoSession()
   1403 //
   1404 //       Function to process a command with no session associated. The function makes sure all the handles in
   1405 //       the command require no authorization.
   1406 //
   1407 //
   1408 //
   1409 //       Error Returns                     Meaning
   1410 //
   1411 //       TPM_RC_AUTH_MISSING               failure - one or more handles require auth
   1412 //
   1413 TPM_RC
   1414 CheckAuthNoSession(
   1415    TPM_CC               commandCode,               //   IN:   Command Code
   1416    UINT32               handleNum,                 //   IN:   number of handles in command
   1417    TPM_HANDLE           handles[],                 //   IN:   array of handle
   1418    BYTE                *parmBufferStart,           //   IN:   start of parameter buffer
   1419    UINT32               parmBufferSize             //   IN:   size of parameter buffer
   1420    )
   1421 {
   1422    UINT32 i;
   1423    TPM_RC                result = TPM_RC_SUCCESS;
   1424    // Check if the commandCode requires authorization
   1425    for(i = 0; i < handleNum; i++)
   1426    {
   1427        if(CommandAuthRole(commandCode, i) != AUTH_NONE)
   1428            return TPM_RC_AUTH_MISSING;
   1429    }
   1430 #ifdef TPM_CC_GetCommandAuditDigest
   1431    // Check if the command should be audited.
   1432    result = CheckCommandAudit(commandCode, handleNum, handles,
   1433                               parmBufferStart, parmBufferSize);
   1434    if(result != TPM_RC_SUCCESS) return result;
   1435 #endif
   1436    // Initialize number of sessions to be 0
   1437    s_sessionNum = 0;
   1438    return TPM_RC_SUCCESS;
   1439 }
   1440 //
   1441 //
   1442 //            Response Session Processing
   1443 //
   1444 //            Introduction
   1445 //
   1446 //       The following functions build the session area in a response, and handle the audit sessions (if present).
   1447 //
   1448 //            ComputeRpHash()
   1449 //
   1450 //       Function to compute rpHash (Response Parameter Hash). The rpHash is only computed if there is an
   1451 //       HMAC authorization session and the return code is TPM_RC_SUCCESS.
   1452 //
   1453 static void
   1454 ComputeRpHash(
   1455    TPM_ALG_ID           hashAlg,                   //   IN: hash algorithm to compute rpHash
   1456    TPM_CC               commandCode,               //   IN: commandCode
   1457    UINT32               resParmBufferSize,         //   IN: size of response parameter buffer
   1458    BYTE                *resParmBuffer,             //   IN: response parameter buffer
   1459    TPM2B_DIGEST        *rpHash                     //   OUT: rpHash
   1460    )
   1461 {
   1462    // The command result in rpHash is always TPM_RC_SUCCESS.
   1463    TPM_RC      responseCode = TPM_RC_SUCCESS;
   1464    HASH_STATE hashState;
   1465    //     rpHash := hash(responseCode || commandCode || parameters)
   1466     // Initiate hash creation.
   1467     rpHash->t.size = CryptStartHash(hashAlg, &hashState);
   1468     // Add hash constituents.
   1469     CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode);
   1470     CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
   1471     CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer);
   1472     // Complete hash computation.
   1473     CryptCompleteHash2B(&hashState, &rpHash->b);
   1474     return;
   1475 }
   1476 //
   1477 //
   1478 //             InitAuditSession()
   1479 //
   1480 //       This function initializes the audit data in an audit session.
   1481 //
   1482 static void
   1483 InitAuditSession(
   1484     SESSION              *session             // session to be initialized
   1485     )
   1486 {
   1487     // Mark session as an audit session.
   1488     session->attributes.isAudit = SET;
   1489     // Audit session can not be bound.
   1490     session->attributes.isBound = CLEAR;
   1491     // Size of the audit log is the size of session hash algorithm digest.
   1492     session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
   1493     // Set the original digest value to be 0.
   1494     MemorySet(&session->u2.auditDigest.t.buffer,
   1495               0,
   1496               session->u2.auditDigest.t.size);
   1497     return;
   1498 }
   1499 //
   1500 //
   1501 //             Audit()
   1502 //
   1503 //       This function updates the audit digest in an audit session.
   1504 //
   1505 static void
   1506 Audit(
   1507     SESSION              *auditSession,            //   IN:    loaded audit session
   1508     TPM_CC                commandCode,             //   IN:    commandCode
   1509     UINT32                resParmBufferSize,       //   IN:    size of response parameter buffer
   1510     BYTE                 *resParmBuffer            //   IN:    response parameter buffer
   1511     )
   1512 {
   1513     TPM2B_DIGEST          rpHash;                  // rpHash for response
   1514     HASH_STATE            hashState;
   1515     // Compute rpHash
   1516     ComputeRpHash(auditSession->authHashAlg,
   1517                   commandCode,
   1518                   resParmBufferSize,
   1519                   resParmBuffer,
   1520                   &rpHash);
   1521    // auditDigestnew :=      hash (auditDigestold || cpHash || rpHash)
   1522    // Start hash computation.
   1523    CryptStartHash(auditSession->authHashAlg, &hashState);
   1524    // Add old digest.
   1525    CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b);
   1526    // Add cpHash and rpHash.
   1527    CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b);
   1528    CryptUpdateDigest2B(&hashState, &rpHash.b);
   1529    // Finalize the hash.
   1530    CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b);
   1531    return;
   1532 }
   1533 #ifdef TPM_CC_GetCommandAuditDigest
   1534 //
   1535 //
   1536 //            CommandAudit()
   1537 //
   1538 //       This function updates the command audit digest.
   1539 //
   1540 static void
   1541 CommandAudit(
   1542    TPM_CC              commandCode,       // IN: commandCode
   1543    UINT32              resParmBufferSize, // IN: size of response parameter buffer
   1544    BYTE               *resParmBuffer      // IN: response parameter buffer
   1545    )
   1546 {
   1547    if(CommandAuditIsRequired(commandCode))
   1548    {
   1549        TPM2B_DIGEST    rpHash;        // rpHash for response
   1550        HASH_STATE      hashState;
   1551          // Compute rpHash.
   1552          ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize,
   1553                        resParmBuffer, &rpHash);
   1554          // If the digest.size is one, it indicates the special case of changing
   1555          // the audit hash algorithm. For this case, no audit is done on exit.
   1556          // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
   1557          // force an update to the NV on exit so that the change in digest will
   1558          // be recorded. So, it is safe to exit here without setting any flags
   1559          // because the digest change will be written to NV when this code exits.
   1560          if(gr.commandAuditDigest.t.size == 1)
   1561          {
   1562              gr.commandAuditDigest.t.size = 0;
   1563              return;
   1564          }
   1565          // If the digest size is zero, need to start a new digest and increment
   1566          // the audit counter.
   1567          if(gr.commandAuditDigest.t.size == 0)
   1568          {
   1569              gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg);
   1570              MemorySet(gr.commandAuditDigest.t.buffer,
   1571                        0,
   1572                        gr.commandAuditDigest.t.size);
   1573              // Bump the counter and save its value to NV.
   1574              gp.auditCounter++;
   1575              NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
   1576              g_updateNV = TRUE;
   1577 //
   1578          }
   1579          // auditDigestnew :=         hash (auditDigestold || cpHash || rpHash)
   1580          // Start hash computation.
   1581          CryptStartHash(gp.auditHashAlg, &hashState);
   1582          // Add old digest.
   1583          CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b);
   1584          // Add cpHash
   1585          CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b);
   1586          // Add rpHash
   1587          CryptUpdateDigest2B(&hashState, &rpHash.b);
   1588          // Finalize the hash.
   1589          CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b);
   1590     }
   1591     return;
   1592 }
   1593 #endif
   1594 //
   1595 //
   1596 //              UpdateAuditSessionStatus()
   1597 //
   1598 //       Function to update the internal audit related states of a session. It
   1599 //       a) initializes the session as audit session and sets it to be exclusive if this is the first time it is used for
   1600 //          audit or audit reset was requested;
   1601 //       b) reports exclusive audit session;
   1602 //       c) extends audit log; and
   1603 //       d) clears exclusive audit session if no audit session found in the command.
   1604 //
   1605 static void
   1606 UpdateAuditSessionStatus(
   1607     TPM_CC                commandCode,       // IN: commandCode
   1608     UINT32                resParmBufferSize, // IN: size of response parameter buffer
   1609     BYTE                 *resParmBuffer      // IN: response parameter buffer
   1610     )
   1611 {
   1612     UINT32                i;
   1613     TPM_HANDLE            auditSession = TPM_RH_UNASSIGNED;
   1614     // Iterate through sessions
   1615     for (i = 0; i < s_sessionNum; i++)
   1616     {
   1617         SESSION     *session;
   1618          // PW session do not have a loaded session and can not be an audit
   1619          // session either. Skip it.
   1620          if(s_sessionHandles[i] == TPM_RS_PW) continue;
   1621          session = SessionGet(s_sessionHandles[i]);
   1622          // If a session is used for audit
   1623          if(s_attributes[i].audit == SET)
   1624          {
   1625              // An audit session has been found
   1626              auditSession = s_sessionHandles[i];
   1627               // If the session has not been an audit session yet, or
   1628               // the auditSetting bits indicate a reset, initialize it and set
   1629               // it to be the exclusive session
   1630               if(    session->attributes.isAudit == CLEAR
   1631                   || s_attributes[i].auditReset == SET
   1632                 )
   1633               {
   1634                    InitAuditSession(session);
   1635                    g_exclusiveAuditSession = auditSession;
   1636               }
   1637               else
   1638               {
   1639                    // Check if the audit session is the current exclusive audit
   1640                    // session and, if not, clear previous exclusive audit session.
   1641                    if(g_exclusiveAuditSession != auditSession)
   1642                        g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
   1643               }
   1644               // Report audit session exclusivity.
   1645               if(g_exclusiveAuditSession == auditSession)
   1646               {
   1647                   s_attributes[i].auditExclusive = SET;
   1648               }
   1649               else
   1650               {
   1651                   s_attributes[i].auditExclusive = CLEAR;
   1652               }
   1653               // Extend audit log.
   1654               Audit(session, commandCode, resParmBufferSize, resParmBuffer);
   1655          }
   1656    }
   1657    // If no audit session is found in the command, and the command allows
   1658    // a session then, clear the current exclusive
   1659    // audit session.
   1660    if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode))
   1661    {
   1662        g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
   1663    }
   1664    return;
   1665 }
   1666 //
   1667 //
   1668 //              ComputeResponseHMAC()
   1669 //
   1670 //       Function to compute HMAC for authorization session in a response.
   1671 //
   1672 static void
   1673 ComputeResponseHMAC(
   1674    UINT32              sessionIndex,         //   IN: session index to be processed
   1675    SESSION            *session,              //   IN: loaded session
   1676    TPM_CC              commandCode,          //   IN: commandCode
   1677    TPM2B_NONCE        *nonceTPM,             //   IN: nonceTPM
   1678    UINT32              resParmBufferSize,    //   IN: size of response parameter buffer
   1679    BYTE               *resParmBuffer,        //   IN: response parameter buffer
   1680    TPM2B_DIGEST       *hmac                  //   OUT: authHMAC
   1681    )
   1682 {
   1683    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
   1684    TPM2B_KEY        key;       // HMAC key
   1685    BYTE             marshalBuffer[sizeof(TPMA_SESSION)];
   1686    BYTE            *buffer;
   1687    INT32            bufferSize;
   1688    UINT32           marshalSize;
   1689    HMAC_STATE       hmacState;
   1690    TPM2B_DIGEST     rp_hash;
   1691 //
   1692    // Compute rpHash.
   1693    ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize,
   1694                  resParmBuffer, &rp_hash);
   1695    // Generate HMAC key
   1696    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
   1697    // Check if the session has an associated handle and the associated entity is
   1698    // the one that the session is bound to.
   1699    // If not bound, add the authValue of this entity to the HMAC key.
   1700    if(   s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED
   1701       &&    !( HandleGetType(s_sessionHandles[sessionIndex])
   1702                  == TPM_HT_POLICY_SESSION
   1703          &&   session->attributes.isAuthValueNeeded == CLEAR)
   1704       && !session->attributes.requestWasBound)
   1705    {
   1706        pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
   1707        key.t.size = key.t.size +
   1708                        EntityGetAuthValue(s_associatedHandles[sessionIndex],
   1709                                           (AUTH_VALUE *)&key.t.buffer[key.t.size]);
   1710    }
   1711    // if the HMAC key size for a policy session is 0, the response HMAC is
   1712    // computed according to the input HMAC
   1713    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
   1714        && key.t.size == 0
   1715        && s_inputAuthValues[sessionIndex].t.size == 0)
   1716    {
   1717        hmac->t.size = 0;
   1718        return;
   1719    }
   1720    // Start HMAC computation.
   1721    hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
   1722    // Add hash components.
   1723    CryptUpdateDigest2B(&hmacState, &rp_hash.b);
   1724    CryptUpdateDigest2B(&hmacState, &nonceTPM->b);
   1725    CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
   1726    // Add session attributes.
   1727    buffer = marshalBuffer;
   1728    bufferSize = sizeof(TPMA_SESSION);
   1729    marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, &bufferSize);
   1730    CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
   1731    // Finalize HMAC.
   1732    CryptCompleteHMAC2B(&hmacState, &hmac->b);
   1733    return;
   1734 }
   1735 //
   1736 //
   1737 //           BuildSingleResponseAuth()
   1738 //
   1739 //       Function to compute response for an authorization session.
   1740 //
   1741 static void
   1742 BuildSingleResponseAuth(
   1743    UINT32              sessionIndex,          //   IN: session index to be processed
   1744    TPM_CC              commandCode,           //   IN: commandCode
   1745    UINT32              resParmBufferSize,     //   IN: size of response parameter buffer
   1746    BYTE               *resParmBuffer,         //   IN: response parameter buffer
   1747    TPM2B_AUTH         *auth                   //   OUT: authHMAC
   1748    )
   1749 //
   1750 {
   1751    // For password authorization, field is empty.
   1752    if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
   1753    {
   1754        auth->t.size = 0;
   1755    }
   1756    else
   1757    {
   1758        // Fill in policy/HMAC based session response.
   1759        SESSION     *session = SessionGet(s_sessionHandles[sessionIndex]);
   1760           // If the session is a policy session with isPasswordNeeded SET, the auth
   1761           // field is empty.
   1762           if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
   1763                    && session->attributes.isPasswordNeeded == SET)
   1764                auth->t.size = 0;
   1765           else
   1766                // Compute response HMAC.
   1767                ComputeResponseHMAC(sessionIndex,
   1768                                    session,
   1769                                    commandCode,
   1770                                    &session->nonceTPM,
   1771                                    resParmBufferSize,
   1772                                    resParmBuffer,
   1773                                    auth);
   1774    }
   1775    return;
   1776 }
   1777 //
   1778 //
   1779 //            UpdateTPMNonce()
   1780 //
   1781 //       Updates TPM nonce in both internal session or response if applicable.
   1782 //
   1783 static void
   1784 UpdateTPMNonce(
   1785    UINT16               noncesSize,       // IN: number of elements in 'nonces' array
   1786    TPM2B_NONCE          nonces[]          // OUT: nonceTPM
   1787    )
   1788 {
   1789    UINT32      i;
   1790    pAssert(noncesSize >= s_sessionNum);
   1791    for(i = 0; i < s_sessionNum; i++)
   1792    {
   1793        SESSION     *session;
   1794        // For PW session, nonce is 0.
   1795        if(s_sessionHandles[i] == TPM_RS_PW)
   1796        {
   1797            nonces[i].t.size = 0;
   1798            continue;
   1799        }
   1800        session = SessionGet(s_sessionHandles[i]);
   1801        // Update nonceTPM in both internal session and response.
   1802        CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
   1803        nonces[i] = session->nonceTPM;
   1804    }
   1805    return;
   1806 }
   1807 //
   1808 //
   1809 //           UpdateInternalSession()
   1810 //
   1811 //       Updates internal sessions:
   1812 //
   1813 //
   1814 //       a) Restarts session time, and
   1815 //       b) Clears a policy session since nonce is rolling.
   1816 //
   1817 static void
   1818 UpdateInternalSession(
   1819    void
   1820    )
   1821 {
   1822    UINT32      i;
   1823    for(i = 0; i < s_sessionNum; i++)
   1824    {
   1825        // For PW session, no update.
   1826        if(s_sessionHandles[i] == TPM_RS_PW) continue;
   1827           if(s_attributes[i].continueSession == CLEAR)
   1828           {
   1829                // Close internal session.
   1830                SessionFlush(s_sessionHandles[i]);
   1831           }
   1832           else
   1833           {
   1834                // If nonce is rolling in a policy session, the policy related data
   1835                // will be re-initialized.
   1836                if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION)
   1837                {
   1838                    SESSION     *session = SessionGet(s_sessionHandles[i]);
   1839                    // When the nonce rolls it starts a new timing interval for the
   1840                    // policy session.
   1841                    SessionResetPolicyData(session);
   1842                    session->startTime = go.clock;
   1843                }
   1844           }
   1845    }
   1846    return;
   1847 }
   1848 //
   1849 //
   1850 //              BuildResponseSession()
   1851 //
   1852 //       Function to build Session buffer in a response.
   1853 //
   1854 void
   1855 BuildResponseSession(
   1856    TPM_ST               tag,               //    IN: tag
   1857    TPM_CC               commandCode,       //    IN: commandCode
   1858    UINT32               resHandleSize,     //    IN: size of response handle buffer
   1859    UINT32               resParmSize,       //    IN: size of response parameter buffer
   1860    UINT32              *resSessionSize     //    OUT: response session area
   1861    )
   1862 {
   1863    BYTE                *resParmBuffer;
   1864    INT32                bufferSize;
   1865    TPM2B_NONCE      responseNonces[MAX_SESSION_NUM];
   1866    // Compute response parameter buffer start.
   1867    resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) +
   1868                    sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize;
   1869    bufferSize = MAX_RESPONSE_SIZE - sizeof(TPM_ST) - sizeof(UINT32) -
   1870                 sizeof(TPM_RC) - resHandleSize;
   1871    // For TPM_ST_SESSIONS, there is parameterSize field.
   1872    if(tag == TPM_ST_SESSIONS) {
   1873        resParmBuffer += sizeof(UINT32);
   1874        bufferSize -= sizeof(UINT32);
   1875    }
   1876    // Session nonce should be updated before parameter encryption
   1877    if(tag == TPM_ST_SESSIONS)
   1878    {
   1879          UpdateTPMNonce(MAX_SESSION_NUM, responseNonces);
   1880          // Encrypt first parameter if applicable. Parameter encryption should
   1881          // happen after nonce update and before any rpHash is computed.
   1882          // If the encrypt session is associated with a handle, the authValue of
   1883          // this handle will be concatenated with sessionAuth to generate
   1884          // encryption key, no matter if the handle is the session bound entity
   1885          // or not. The authValue is added to sessionAuth only when the authValue
   1886          // is available.
   1887          if(s_encryptSessionIndex != UNDEFINED_INDEX)
   1888          {
   1889              UINT32          size;
   1890              TPM2B_AUTH      extraKey;
   1891              // Get size of the leading size field
   1892              if(    s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED
   1893                  && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex],
   1894                                          commandCode, s_encryptSessionIndex)
   1895                )
   1896              {
   1897                   extraKey.b.size =
   1898                       EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
   1899                                          &extraKey.t.buffer);
   1900              }
   1901              else
   1902              {
   1903                   extraKey.b.size = 0;
   1904              }
   1905              size = EncryptSize(commandCode);
   1906              CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
   1907                                        &s_nonceCaller[s_encryptSessionIndex].b,
   1908                                        (UINT16)size,
   1909                                        &extraKey,
   1910                                        resParmBuffer);
   1911          }
   1912    }
   1913    // Audit session should be updated first regardless of the tag.
   1914    // A command with no session may trigger a change of the exclusivity state.
   1915    UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer);
   1916    // Audit command.
   1917    CommandAudit(commandCode, resParmSize, resParmBuffer);
   1918    // Process command with sessions.
   1919    if(tag == TPM_ST_SESSIONS)
   1920    {
   1921        UINT32           i;
   1922        BYTE            *buffer;
   1923        TPM2B_DIGEST     responseAuths[MAX_SESSION_NUM];
   1924          pAssert(s_sessionNum > 0);
   1925          // Iterate over each session in the command session area, and create
   1926          // corresponding sessions for response.
   1927          for(i = 0; i < s_sessionNum; i++)
   1928          {
   1929              BuildSingleResponseAuth(
   1930                                       i,
   1931                                       commandCode,
   1932                                       resParmSize,
   1933                                       resParmBuffer,
   1934                                       &responseAuths[i]);
   1935              // Make sure that continueSession is SET on any Password session.
   1936               // This makes it marginally easier for the management software
   1937               // to keep track of the closed sessions.
   1938               if(    s_attributes[i].continueSession == CLEAR
   1939                   && s_sessionHandles[i] == TPM_RS_PW)
   1940               {
   1941                    s_attributes[i].continueSession = SET;
   1942               }
   1943         }
   1944         // Assemble Response Sessions.
   1945         *resSessionSize = 0;
   1946         buffer = resParmBuffer + resParmSize;
   1947         bufferSize -= resParmSize;
   1948         for(i = 0; i < s_sessionNum; i++)
   1949         {
   1950             *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i],
   1951                                                    &buffer, &bufferSize);
   1952             *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i],
   1953                                                     &buffer, &bufferSize);
   1954             *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i],
   1955                                                     &buffer, &bufferSize);
   1956         }
   1957         // Update internal sessions after completing response buffer computation.
   1958         UpdateInternalSession();
   1959    }
   1960    else
   1961    {
   1962        // Process command with no session.
   1963        *resSessionSize = 0;
   1964    }
   1965    return;
   1966 }
   1967