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//
29BOOL
30IsDAExempted(
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//
80static TPM_RC
81IncrementLockout(
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//
171static BOOL
172IsSessionBindEntity(
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//
208static BOOL
209IsPolicySessionRequired(
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//
258static BOOL
259IsAuthValueAvailable(
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//
364static BOOL
365IsAuthPolicyAvailable(
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//
462static void
463ComputeCpHash(
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//
527static TPM_RC
528CheckPWAuthSession(
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//
555static void
556ComputeCommandHMAC(
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//
680static TPM_RC
681CheckSessionHMAC(
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//
725static TPM_RC
726CheckPolicyAuthSession(
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//
867static TPM_RC
868RetrieveSessionData (
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//
1031static TPM_RC
1032CheckLockedOut(
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//
1098static TPM_RC
1099CheckAuthSession(
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//
1201static TPM_RC
1202CheckCommandAudit(
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//
1245TPM_RC
1246ParseSessionBuffer(
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//
1413TPM_RC
1414CheckAuthNoSession(
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//
1453static void
1454ComputeRpHash(
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//
1482static void
1483InitAuditSession(
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//
1505static void
1506Audit(
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//
1540static void
1541CommandAudit(
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//
1605static void
1606UpdateAuditSessionStatus(
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//
1672static void
1673ComputeResponseHMAC(
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//
1741static void
1742BuildSingleResponseAuth(
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//
1783static void
1784UpdateTPMNonce(
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//
1817static void
1818UpdateInternalSession(
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//
1854void
1855BuildResponseSession(
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