Coverage Report

Created: 2026-01-10 06:45

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