• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
IsDAExempted(TPM_HANDLE handle)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
IncrementLockout(UINT32 sessionIndex)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
IsSessionBindEntity(TPM_HANDLE associatedHandle,SESSION * session)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
IsPolicySessionRequired(TPM_CC commandCode,UINT32 sessionIndex)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
IsAuthValueAvailable(TPM_HANDLE handle,TPM_CC commandCode,UINT32 sessionIndex)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
IsAuthPolicyAvailable(TPM_HANDLE handle,TPM_CC commandCode,UINT32 sessionIndex)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
ComputeCpHash(TPMI_ALG_HASH hashAlg,TPM_CC commandCode,UINT32 handleNum,TPM_HANDLE handles[],UINT32 parmBufferSize,BYTE * parmBuffer,TPM2B_DIGEST * cpHash,TPM2B_DIGEST * nameHash)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
CheckPWAuthSession(UINT32 sessionIndex)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
ComputeCommandHMAC(UINT32 sessionIndex,TPM2B_DIGEST * cpHash,TPM2B_DIGEST * hmac)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
CheckSessionHMAC(UINT32 sessionIndex,TPM2B_DIGEST * cpHash)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
CheckPolicyAuthSession(UINT32 sessionIndex,TPM_CC commandCode,TPM2B_DIGEST * cpHash,TPM2B_DIGEST * nameHash)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
RetrieveSessionData(TPM_CC commandCode,UINT32 * sessionCount,BYTE * sessionBuffer,INT32 bufferSize)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
CheckLockedOut(BOOL lockoutAuthCheck)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
CheckAuthSession(TPM_CC commandCode,UINT32 sessionIndex,TPM2B_DIGEST * cpHash,TPM2B_DIGEST * nameHash)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
CheckCommandAudit(TPM_CC commandCode,UINT32 handleNum,TPM_HANDLE handles[],BYTE * parmBufferStart,UINT32 parmBufferSize)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
ParseSessionBuffer(TPM_CC commandCode,UINT32 handleNum,TPM_HANDLE handles[],BYTE * sessionBufferStart,UINT32 sessionBufferSize,BYTE * parmBufferStart,UINT32 parmBufferSize)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
CheckAuthNoSession(TPM_CC commandCode,UINT32 handleNum,TPM_HANDLE handles[],BYTE * parmBufferStart,UINT32 parmBufferSize)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
ComputeRpHash(TPM_ALG_ID hashAlg,TPM_CC commandCode,UINT32 resParmBufferSize,BYTE * resParmBuffer,TPM2B_DIGEST * rpHash)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
InitAuditSession(SESSION * session)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
Audit(SESSION * auditSession,TPM_CC commandCode,UINT32 resParmBufferSize,BYTE * resParmBuffer)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
CommandAudit(TPM_CC commandCode,UINT32 resParmBufferSize,BYTE * resParmBuffer)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
UpdateAuditSessionStatus(TPM_CC commandCode,UINT32 resParmBufferSize,BYTE * resParmBuffer)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
ComputeResponseHMAC(UINT32 sessionIndex,SESSION * session,TPM_CC commandCode,TPM2B_NONCE * nonceTPM,UINT32 resParmBufferSize,BYTE * resParmBuffer,TPM2B_DIGEST * hmac)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
BuildSingleResponseAuth(UINT32 sessionIndex,TPM_CC commandCode,UINT32 resParmBufferSize,BYTE * resParmBuffer,TPM2B_AUTH * auth)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
UpdateTPMNonce(UINT16 noncesSize,TPM2B_NONCE nonces[])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
UpdateInternalSession(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
BuildResponseSession(TPM_ST tag,TPM_CC commandCode,UINT32 resHandleSize,UINT32 resParmSize,UINT32 * resSessionSize)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