Coverage Report

Created: 2023-06-07 06:46

/src/tpm2/SessionProcess.c
Line
Count
Source (jump to first uncovered line)
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
957
{
34
957
     BOOL          result = FALSE;
35
957
     switch(HandleGetType(handle))
36
957
     {
37
844
         case TPM_HT_PERMANENT:
38
             // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
39
             // DA protection.
40
844
             result = (handle != TPM_RH_LOCKOUT);
41
844
             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
113
         case TPM_HT_PCR:
59
             // PCRs are always exempted from DA.
60
113
             result = TRUE;
61
113
             break;
62
0
         default:
63
0
             break;
64
957
   }
65
957
   return result;
66
957
}
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
16
{
85
16
   TPM_HANDLE            handle = s_associatedHandles[sessionIndex];
86
16
   TPM_HANDLE            sessionHandle = s_sessionHandles[sessionIndex];
87
16
   TPM_RC                result;
88
16
   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
16
   if(sessionHandle == TPM_RS_PW)
92
16
   {
93
16
       if(IsDAExempted(handle))
94
13
           return TPM_RC_BAD_AUTH;
95
16
   }
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
3
   if(handle == TPM_RH_LOCKOUT)
113
3
    {
114
3
         pAssert(gp.lockOutAuthEnabled);
115
3
         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
3
         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
3
    }
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
3
    DARegisterFailure(handle);
155
3
    return TPM_RC_AUTH_FAIL;
156
16
}
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
927
{
214
927
    AUTH_ROLE           role = CommandAuthRole(commandCode, sessionIndex);
215
927
    TPM_HT              type = HandleGetType(s_associatedHandles[sessionIndex]);
216
927
    if(role == AUTH_DUP)
217
0
        return TRUE;
218
927
    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
927
    if(type == TPM_HT_PCR)
230
105
    {
231
105
        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
105
    }
241
927
    return FALSE;
242
927
}
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
927
{
265
927
    BOOL             result = FALSE;
266
927
   switch(HandleGetType(handle))
267
927
   {
268
822
       case TPM_HT_PERMANENT:
269
822
           switch(handle)
270
822
           {
271
                   // At this point hierarchy availability has already been
272
                   // checked so primary seed handles are always available here
273
230
               case TPM_RH_OWNER:
274
329
               case TPM_RH_ENDORSEMENT:
275
601
               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
797
               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
822
               case TPM_RH_LOCKOUT:
287
822
                      result = TRUE;
288
822
                      break;
289
0
                  default:
290
                      // Otherwise authValue is not available.
291
0
                      break;
292
822
            }
293
822
            break;
294
822
        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
105
        case TPM_HT_PCR:
336
            // PCR handle.
337
            // authValue is always allowed for PCR
338
105
            result = TRUE;
339
105
            break;
340
0
        default:
341
            // Otherwise, authValue is not available
342
0
            break;
343
927
   }
344
927
   return result;
345
927
}
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
927
{
528
927
   TPM2B_AUTH         authValue;
529
927
   TPM_HANDLE         associatedHandle = s_associatedHandles[sessionIndex];
530
   // Strip trailing zeros from the password.
531
927
   MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]);
532
   // Get the auth value and size.
533
927
   authValue.t.size = EntityGetAuthValue(associatedHandle, &authValue.t.buffer);
534
   // Success if the digests are identical.
535
927
   if(Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &authValue.b))
536
911
   {
537
911
       return TPM_RC_SUCCESS;
538
911
   }
539
16
   else                    // if the digests are not identical
540
16
   {
541
       // Invoke DA protection if applicable.
542
16
       return IncrementLockout(sessionIndex);
543
16
   }
544
927
}
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
1.11k
{
871
1.11k
   int             sessionIndex;
872
1.11k
   int             i;
873
1.11k
   TPM_RC          result;
874
1.11k
   SESSION        *session;
875
1.11k
   TPM_HT          sessionType;
876
1.11k
   s_decryptSessionIndex = UNDEFINED_INDEX;
877
1.11k
   s_encryptSessionIndex = UNDEFINED_INDEX;
878
1.11k
   s_auditSessionIndex = UNDEFINED_INDEX;
879
2.08k
   for(sessionIndex = 0; bufferSize > 0; sessionIndex++)
880
1.14k
   {
881
       // If maximum allowed number of sessions has been parsed, return a size
882
       // error with a session number that is larger than the number of allowed
883
       // sessions
884
1.14k
       if(sessionIndex == MAX_SESSION_NUM)
885
2
           return TPM_RC_SIZE + TPM_RC_S + g_rcIndex[sessionIndex+1];
886
        // make sure that the associated handle for each session starts out
887
        // unassigned
888
1.14k
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
889
        // First parameter: Session handle.
890
1.14k
        result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
891
1.14k
                                                &sessionBuffer, &bufferSize, TRUE);
892
1.14k
        if(result != TPM_RC_SUCCESS)
893
114
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
894
        // Second parameter: Nonce.
895
1.03k
        result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
896
1.03k
                                       &sessionBuffer, &bufferSize);
897
1.03k
        if(result != TPM_RC_SUCCESS)
898
10
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
899
        // Third parameter: sessionAttributes.
900
1.02k
        result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
901
1.02k
                                        &sessionBuffer, &bufferSize);
902
1.02k
        if(result != TPM_RC_SUCCESS)
903
6
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
904
        // Fourth parameter: authValue (PW or HMAC).
905
1.01k
        result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
906
1.01k
                                      &sessionBuffer, &bufferSize);
907
1.01k
        if(result != TPM_RC_SUCCESS)
908
33
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
909
982
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
910
976
        {
911
            // A PWAP session needs additional processing.
912
            //      Can't have any attributes set other than continueSession bit
913
976
            if(    s_attributes[sessionIndex].encrypt
914
976
                || s_attributes[sessionIndex].decrypt
915
976
                || s_attributes[sessionIndex].audit
916
976
                || s_attributes[sessionIndex].auditExclusive
917
976
                || s_attributes[sessionIndex].auditReset
918
976
              )
919
7
                 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
920
              //     The nonce size must be zero.
921
969
              if(s_nonceCaller[sessionIndex].t.size != 0)
922
2
                  return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex];
923
967
            continue;
924
969
        }
925
        // For not password sessions...
926
        // Find out if the session is loaded.
927
6
        if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
928
6
            return TPM_RC_REFERENCE_S0 + sessionIndex;
929
0
        sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
930
0
        session = SessionGet(s_sessionHandles[sessionIndex]);
931
        // Check if the session is an HMAC/policy session.
932
0
         if(        (   session->attributes.isPolicy == SET
933
0
                     && sessionType == TPM_HT_HMAC_SESSION
934
0
                    )
935
0
                 || (    session->attributes.isPolicy == CLEAR
936
0
                      && sessionType == TPM_HT_POLICY_SESSION
937
0
                    )
938
0
             )
939
0
                  return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
940
         // Check that this handle has not previously been used.
941
0
         for(i = 0; i < sessionIndex; i++)
942
0
         {
943
0
             if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
944
0
                 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
945
0
         }
946
         // If the session is used for parameter encryption or audit as well, set
947
         // the corresponding indices.
948
         // First process decrypt.
949
0
         if(s_attributes[sessionIndex].decrypt)
950
0
         {
951
             // Check if the commandCode allows command parameter encryption.
952
0
             if(DecryptSize(commandCode) == 0)
953
0
                 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
954
                  // Encrypt attribute can only appear in one session
955
0
                  if(s_decryptSessionIndex != UNDEFINED_INDEX)
956
0
                      return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
957
                  // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
958
0
                  if(session->symmetric.algorithm == TPM_ALG_NULL)
959
0
                      return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
960
                  // All checks passed, so set the index for the session used to decrypt
961
                  // a command parameter.
962
0
                  s_decryptSessionIndex = sessionIndex;
963
0
         }
964
         // Now process encrypt.
965
0
         if(s_attributes[sessionIndex].encrypt)
966
0
         {
967
             // Check if the commandCode allows response parameter encryption.
968
0
             if(EncryptSize(commandCode) == 0)
969
0
                 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
970
                  // Encrypt attribute can only appear in one session.
971
0
                  if(s_encryptSessionIndex != UNDEFINED_INDEX)
972
0
                      return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
973
                  // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
974
0
                  if(session->symmetric.algorithm == TPM_ALG_NULL)
975
0
                      return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
976
                  // All checks passed, so set the index for the session used to encrypt
977
                  // a response parameter.
978
0
                  s_encryptSessionIndex = sessionIndex;
979
0
         }
980
         // At last process audit.
981
0
         if(s_attributes[sessionIndex].audit)
982
0
         {
983
             // Audit attribute can only appear in one session.
984
0
             if(s_auditSessionIndex != UNDEFINED_INDEX)
985
0
                 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
986
               // An audit session can not be policy session.
987
0
               if(    HandleGetType(s_sessionHandles[sessionIndex])
988
0
                   == TPM_HT_POLICY_SESSION)
989
0
                    return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
990
               // If this is a reset of the audit session, or the first use
991
               // of the session as an audit session, it doesn't matter what
992
               // the exclusive state is. The session will become exclusive.
993
0
               if(    s_attributes[sessionIndex].auditReset == CLEAR
994
0
                   && session->attributes.isAudit == SET)
995
0
               {
996
                    // Not first use or reset. If auditExlusive is SET, then this
997
                    // session must be the current exclusive session.
998
0
                    if(    s_attributes[sessionIndex].auditExclusive == SET
999
0
                        && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
1000
0
                        return TPM_RC_EXCLUSIVE;
1001
0
               }
1002
0
               s_auditSessionIndex = sessionIndex;
1003
0
         }
1004
         // Initialize associated handle as undefined. This will be changed when
1005
         // the handles are processed.
1006
0
         s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1007
0
    }
1008
    // Set the number of sessions found.
1009
935
    *sessionCount = sessionIndex;
1010
935
    return TPM_RC_SUCCESS;
1011
1.11k
}
1012
//
1013
//
1014
//             CheckLockedOut()
1015
//
1016
//      This function checks to see if the TPM is in lockout. This function should only be called if the entity being
1017
//      checked is subject to DA protection. The TPM is in lockout if the NV is not available and a DA write is
1018
//      pending. Otherwise the TPM is locked out if checking for lockoutAuth (lockoutAuthCheck == TRUE) and
1019
//      use of lockoutAuth is disabled, or failedTries >= maxTries
1020
//
1021
//      Error Returns                    Meaning
1022
//
1023
//      TPM_RC_NV_RATE                   NV is rate limiting
1024
//      TPM_RC_NV_UNAVAILABLE            NV is not available at this time
1025
//      TPM_RC_LOCKOUT                   TPM is in lockout
1026
//
1027
static TPM_RC
1028
CheckLockedOut(
1029
    BOOL                 lockoutAuthCheck             // IN: TRUE if checking is for lockoutAuth
1030
    )
1031
25
{
1032
25
    TPM_RC         result;
1033
    // If NV is unavailable, and current cycle state recorded in NV is not
1034
    // SHUTDOWN_NONE, refuse to check any authorization because we would
1035
    // not be able to handle a DA failure.
1036
25
    result = NvIsAvailable();
1037
25
    if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE)
1038
0
        return result;
1039
    // Check if DA info needs to be updated in NV.
1040
25
    if(s_DAPendingOnNV)
1041
0
    {
1042
         // If NV is accessible, ...
1043
0
         if(result == TPM_RC_SUCCESS)
1044
0
         {
1045
              // ... write the pending DA data and proceed.
1046
0
              NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED,
1047
0
                              &gp.lockOutAuthEnabled);
1048
0
              NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
1049
0
              g_updateNV = TRUE;
1050
0
              s_DAPendingOnNV = FALSE;
1051
0
         }
1052
0
         else
1053
0
         {
1054
              // Otherwise no authorization can be checked.
1055
0
              return result;
1056
0
         }
1057
0
   }
1058
   // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1059
   // is disabled...
1060
25
   if(lockoutAuthCheck)
1061
25
   {
1062
25
       if(gp.lockOutAuthEnabled == FALSE)
1063
0
           return TPM_RC_LOCKOUT;
1064
25
   }
1065
0
   else
1066
0
   {
1067
       // ... or if the number of failed tries has been maxed out.
1068
0
       if(gp.failedTries >= gp.maxTries)
1069
0
           return TPM_RC_LOCKOUT;
1070
0
   }
1071
25
   return TPM_RC_SUCCESS;
1072
25
}
1073
//
1074
//
1075
//           CheckAuthSession()
1076
//
1077
//      This function checks that the authorization session properly authorizes the use of the associated handle.
1078
//
1079
//      Error Returns                     Meaning
1080
//
1081
//      TPM_RC_LOCKOUT                    entity is protected by DA and TPM is in lockout, or TPM is locked out
1082
//                                        on NV update pending on DA parameters
1083
//      TPM_RC_PP                         Physical Presence is required but not provided
1084
//      TPM_RC_AUTH_FAIL                  HMAC or PW authorization failed with DA side-effects (can be a
1085
//                                        policy session)
1086
//      TPM_RC_BAD_AUTH                   HMAC or PW authorization failed without DA side-effects (can be a
1087
//                                        policy session)
1088
//      TPM_RC_POLICY_FAIL                if policy session fails
1089
//      TPM_RC_POLICY_CC                  command code of policy was wrong
1090
//      TPM_RC_EXPIRED                    the policy session has expired
1091
//      TPM_RC_PCR                        ???
1092
//      TPM_RC_AUTH_UNAVAILABLE           authValue or authPolicy unavailable
1093
//
1094
static TPM_RC
1095
CheckAuthSession(
1096
   TPM_CC               commandCode,           //   IN:    commandCode
1097
   UINT32               sessionIndex,          //   IN:    index of session to be processed
1098
   TPM2B_DIGEST        *cpHash,                //   IN:    cpHash
1099
   TPM2B_DIGEST        *nameHash               //   IN:    nameHash
1100
//
1101
   )
1102
927
{
1103
927
   TPM_RC              result;
1104
927
   SESSION            *session = NULL;
1105
927
   TPM_HANDLE          sessionHandle = s_sessionHandles[sessionIndex];
1106
927
   TPM_HANDLE          associatedHandle = s_associatedHandles[sessionIndex];
1107
927
   TPM_HT              sessionHandleType = HandleGetType(sessionHandle);
1108
927
   pAssert(sessionHandle != TPM_RH_UNASSIGNED);
1109
927
   if(sessionHandle != TPM_RS_PW)
1110
0
       session = SessionGet(sessionHandle);
1111
927
   pAssert(sessionHandleType != TPM_HT_POLICY_SESSION || session != NULL);
1112
   // If the authorization session is not a policy session, or if the policy
1113
   // session requires authorization, then check lockout.
1114
927
   if(    sessionHandleType != TPM_HT_POLICY_SESSION
1115
927
      || session->attributes.isAuthValueNeeded
1116
927
      || session->attributes.isPasswordNeeded)
1117
927
   {
1118
       // See if entity is subject to lockout.
1119
927
       if(!IsDAExempted(associatedHandle))
1120
25
       {
1121
           // If NV is unavailable, and current cycle state recorded in NV is not
1122
           // SHUTDOWN_NONE, refuse to check any authorization because we would
1123
           // not be able to handle a DA failure.
1124
25
           result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
1125
25
           if(result != TPM_RC_SUCCESS)
1126
0
               return result;
1127
25
       }
1128
927
   }
1129
927
   if(associatedHandle == TPM_RH_PLATFORM)
1130
272
   {
1131
       // If the physical presence is required for this command, check for PP
1132
       // assertion. If it isn't asserted, no point going any further.
1133
272
       if(    PhysicalPresenceIsRequired(commandCode)
1134
272
           && !_plat__PhysicalPresenceAsserted()
1135
272
         )
1136
0
            return TPM_RC_PP;
1137
272
   }
1138
   // If a policy session is required, make sure that it is being used.
1139
927
   if(   IsPolicySessionRequired(commandCode, sessionIndex)
1140
927
      && sessionHandleType != TPM_HT_POLICY_SESSION)
1141
0
       return TPM_RC_AUTH_TYPE;
1142
   // If this is a PW authorization, check it and return.
1143
927
   if(sessionHandle == TPM_RS_PW)
1144
927
   {
1145
927
       if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1146
927
            return CheckPWAuthSession(sessionIndex);
1147
0
       else
1148
0
            return TPM_RC_AUTH_UNAVAILABLE;
1149
927
   }
1150
   // If this is a policy session, ...
1151
0
   if(sessionHandleType == TPM_HT_POLICY_SESSION)
1152
0
   {
1153
       // ... see if the entity has a policy, ...
1154
0
       if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex))
1155
0
            return TPM_RC_AUTH_UNAVAILABLE;
1156
       // ... and check the policy session.
1157
0
       result = CheckPolicyAuthSession(sessionIndex, commandCode,
1158
0
                                        cpHash, nameHash);
1159
0
       if (result != TPM_RC_SUCCESS)
1160
0
            return result;
1161
0
   }
1162
0
   else
1163
0
   {
1164
       // For non policy, the entity being accessed must allow authorization
1165
       // with an auth value. This is required even if the auth value is not
1166
       // going to be used in an HMAC because it is bound.
1167
0
       if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1168
0
           return TPM_RC_AUTH_UNAVAILABLE;
1169
0
   }
1170
   // At this point, the session must be either a policy or an HMAC session.
1171
0
   session = SessionGet(s_sessionHandles[sessionIndex]);
1172
0
   if(         sessionHandleType == TPM_HT_POLICY_SESSION
1173
0
         &&    session->attributes.isPasswordNeeded == SET)
1174
0
   {
1175
         // For policy session that requires a password, check it as PWAP session.
1176
0
         return CheckPWAuthSession(sessionIndex);
1177
0
   }
1178
0
   else
1179
0
   {
1180
       // For other policy or HMAC sessions, have its HMAC checked.
1181
0
       return CheckSessionHMAC(sessionIndex, cpHash);
1182
0
   }
1183
0
}
1184
#ifdef    TPM_CC_GetCommandAuditDigest
1185
//
1186
//
1187
//            CheckCommandAudit()
1188
//
1189
//       This function checks if the current command may trigger command audit, and if it is safe to perform the
1190
//       action.
1191
//
1192
//       Error Returns                     Meaning
1193
//
1194
//       TPM_RC_NV_UNAVAILABLE             NV is not available for write
1195
//       TPM_RC_NV_RATE                    NV is rate limiting
1196
//
1197
static TPM_RC
1198
CheckCommandAudit(
1199
   TPM_CC               commandCode,                   //   IN:   Command code
1200
   UINT32               handleNum,                     //   IN:   number of element in handle array
1201
   TPM_HANDLE           handles[],                     //   IN:   array of handle
1202
   BYTE                *parmBufferStart,               //   IN:   start of parameter buffer
1203
   UINT32               parmBufferSize                 //   IN:   size of parameter buffer
1204
   )
1205
9.38k
{
1206
9.38k
   TPM_RC          result = TPM_RC_SUCCESS;
1207
   // If audit is implemented, need to check to see if auditing is being done
1208
   // for this command.
1209
9.38k
   if(CommandAuditIsRequired(commandCode))
1210
0
   {
1211
       // If the audit digest is clear and command audit is required, NV must be
1212
       // available so that TPM2_GetCommandAuditDigest() is able to increment
1213
       // audit counter. If NV is not available, the function bails out to prevent
1214
       // the TPM from attempting an operation that would fail anyway.
1215
0
       if(     gr.commandAuditDigest.t.size == 0
1216
0
           || commandCode == TPM_CC_GetCommandAuditDigest)
1217
0
       {
1218
0
            result = NvIsAvailable();
1219
0
            if(result != TPM_RC_SUCCESS)
1220
0
                return result;
1221
0
       }
1222
0
       ComputeCpHash(gp.auditHashAlg, commandCode, handleNum,
1223
0
                         handles, parmBufferSize, parmBufferStart,
1224
0
                         &s_cpHashForCommandAudit, NULL);
1225
0
    }
1226
9.38k
   return TPM_RC_SUCCESS;
1227
9.38k
}
1228
#endif
1229
//
1230
//
1231
//           ParseSessionBuffer()
1232
//
1233
//       This function is the entry function for command session processing. It iterates sessions in session area
1234
//       and reports if the required authorization has been properly provided. It also processes audit session and
1235
//       passes the information of encryption sessions to parameter encryption module.
1236
//
1237
//       Error Returns                   Meaning
1238
//
1239
//       various                         parsing failure or authorization failure
1240
//
1241
TPM_RC
1242
ParseSessionBuffer(
1243
    TPM_CC              commandCode,                    //   IN:   Command code
1244
    UINT32              handleNum,                      //   IN:   number of element in handle array
1245
    TPM_HANDLE          handles[],                      //   IN:   array of handle
1246
    BYTE               *sessionBufferStart,             //   IN:   start of session buffer
1247
    UINT32              sessionBufferSize,              //   IN:   size of session buffer
1248
    BYTE               *parmBufferStart,                //   IN:   start of parameter buffer
1249
    UINT32              parmBufferSize                  //   IN:   size of parameter buffer
1250
    )
1251
1.11k
{
1252
1.11k
    TPM_RC              result;
1253
1.11k
    UINT32              i;
1254
1.11k
    INT32               size = 0;
1255
1.11k
    TPM2B_AUTH          extraKey;
1256
1.11k
    UINT32              sessionIndex;
1257
1.11k
    SESSION            *session;
1258
1.11k
    TPM2B_DIGEST        cpHash;
1259
1.11k
    TPM2B_DIGEST        nameHash;
1260
1.11k
    TPM_ALG_ID          cpHashAlg = TPM_ALG_NULL;             // algID for the last computed
1261
                                                              // cpHash
1262
    // Check if a command allows any session in its session area.
1263
1.11k
    if(!IsSessionAllowed(commandCode))
1264
2
        return TPM_RC_AUTH_CONTEXT;
1265
    // Default-initialization.
1266
1.11k
    s_sessionNum = 0;
1267
1.11k
    cpHash.t.size = 0;
1268
1.11k
    result = RetrieveSessionData(commandCode, &s_sessionNum,
1269
1.11k
                                 sessionBufferStart, sessionBufferSize);
1270
1.11k
    if(result != TPM_RC_SUCCESS)
1271
180
        return result;
1272
    // There is no command in the TPM spec that has more handles than
1273
    // MAX_SESSION_NUM.
1274
935
    pAssert(handleNum <= MAX_SESSION_NUM);
1275
    // Associate the session with an authorization handle.
1276
1.86k
    for(i = 0; i < handleNum; i++)
1277
929
    {
1278
929
        if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1279
927
        {
1280
            // If the received session number is less than the number of handle
1281
            // that requires authorization, an error should be returned.
1282
             // Note: for all the TPM 2.0 commands, handles requiring
1283
             // authorization come first in a command input.
1284
927
             if(i > (s_sessionNum - 1))
1285
0
                 return TPM_RC_AUTH_MISSING;
1286
             // Record the handle associated with the authorization session
1287
927
             s_associatedHandles[i] = handles[i];
1288
927
         }
1289
929
   }
1290
   // Consistency checks are done first to avoid auth failure when the command
1291
   // will not be executed anyway.
1292
1.84k
   for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++)
1293
937
   {
1294
       // PW session must be an authorization session
1295
937
       if(s_sessionHandles[sessionIndex] == TPM_RS_PW )
1296
937
       {
1297
937
            if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
1298
10
                return TPM_RC_HANDLE + g_rcIndex[sessionIndex];
1299
937
       }
1300
0
       else
1301
0
       {
1302
0
            session = SessionGet(s_sessionHandles[sessionIndex]);
1303
             // A trial session can not appear in session area, because it cannot
1304
             // be used for authorization, audit or encrypt/decrypt.
1305
0
             if(session->attributes.isTrialPolicy == SET)
1306
0
                 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1307
             // See if the session is bound to a DA protected entity
1308
             // NOTE: Since a policy session is never bound, a policy is still
1309
             // usable even if the object is DA protected and the TPM is in
1310
             // lockout.
1311
0
             if(session->attributes.isDaBound == SET)
1312
0
             {
1313
0
                 result = CheckLockedOut(session->attributes.isLockoutBound == SET);
1314
0
                 if(result != TPM_RC_SUCCESS)
1315
0
                     return result;
1316
0
             }
1317
             // If the current cpHash is the right one, don't re-compute.
1318
0
             if(cpHashAlg != session->authHashAlg)    // different so compute
1319
0
             {
1320
0
                 cpHashAlg = session->authHashAlg;    // save this new algID
1321
0
                 ComputeCpHash(session->authHashAlg, commandCode, handleNum,
1322
0
                               handles, parmBufferSize, parmBufferStart,
1323
0
                               &cpHash, &nameHash);
1324
0
             }
1325
             // If this session is for auditing, save the cpHash.
1326
0
             if(s_attributes[sessionIndex].audit)
1327
0
                 s_cpHashForAudit = cpHash;
1328
0
         }
1329
         // if the session has an associated handle, check the auth
1330
927
         if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
1331
927
         {
1332
927
              result = CheckAuthSession(commandCode, sessionIndex,
1333
927
                                        &cpHash, &nameHash);
1334
927
              if(result != TPM_RC_SUCCESS)
1335
16
                  return RcSafeAddToResult(result,
1336
927
                                           TPM_RC_S + g_rcIndex[sessionIndex]);
1337
927
         }
1338
0
         else
1339
0
         {
1340
              // a session that is not for authorization must either be encrypt,
1341
              // decrypt, or audit
1342
0
              if(     s_attributes[sessionIndex].audit == CLEAR
1343
0
                   && s_attributes[sessionIndex].encrypt == CLEAR
1344
0
                   && s_attributes[sessionIndex].decrypt == CLEAR)
1345
0
                   return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1346
               // check HMAC for encrypt/decrypt/audit only sessions
1347
0
               result = CheckSessionHMAC(sessionIndex, &cpHash);
1348
0
               if(result != TPM_RC_SUCCESS)
1349
0
                   return RcSafeAddToResult(result,
1350
0
                                            TPM_RC_S + g_rcIndex[sessionIndex]);
1351
0
          }
1352
927
   }
1353
909
#ifdef TPM_CC_GetCommandAuditDigest
1354
   // Check if the command should be audited.
1355
909
   result = CheckCommandAudit(commandCode, handleNum, handles,
1356
909
                              parmBufferStart, parmBufferSize);
1357
909
   if(result != TPM_RC_SUCCESS)
1358
0
       return result;              // No session number to reference
1359
909
#endif
1360
   // Decrypt the first parameter if applicable. This should be the last operation
1361
   // in session processing.
1362
   // If the encrypt session is associated with a handle and the handle's
1363
   // authValue is available, then authValue is concatenated with sessionAuth to
1364
   // generate encryption key, no matter if the handle is the session bound entity
1365
   // or not.
1366
909
   if(s_decryptSessionIndex != UNDEFINED_INDEX)
1367
0
   {
1368
       // Get size of the leading size field in decrypt parameter
1369
0
       if(    s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED
1370
0
           && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex],
1371
0
                                   commandCode,
1372
0
                                   s_decryptSessionIndex)
1373
0
         )
1374
0
       {
1375
0
            extraKey.b.size=
1376
0
                EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex],
1377
0
                                   &extraKey.t.buffer);
1378
0
       }
1379
0
       else
1380
0
       {
1381
0
            extraKey.b.size = 0;
1382
0
       }
1383
0
       size = DecryptSize(commandCode);
1384
0
       result = CryptParameterDecryption(
1385
0
                     s_sessionHandles[s_decryptSessionIndex],
1386
0
                     &s_nonceCaller[s_decryptSessionIndex].b,
1387
0
                     parmBufferSize, (UINT16)size,
1388
0
                     &extraKey,
1389
0
                     parmBufferStart);
1390
0
       if(result != TPM_RC_SUCCESS)
1391
0
            return RcSafeAddToResult(result,
1392
0
                                     TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
1393
0
   }
1394
909
   return TPM_RC_SUCCESS;
1395
909
}
1396
//
1397
//
1398
//              CheckAuthNoSession()
1399
//
1400
//       Function to process a command with no session associated. The function makes sure all the handles in
1401
//       the command require no authorization.
1402
//
1403
//
1404
//
1405
//       Error Returns                     Meaning
1406
//
1407
//       TPM_RC_AUTH_MISSING               failure - one or more handles require auth
1408
//
1409
TPM_RC
1410
CheckAuthNoSession(
1411
   TPM_CC               commandCode,               //   IN:   Command Code
1412
   UINT32               handleNum,                 //   IN:   number of handles in command
1413
   TPM_HANDLE           handles[],                 //   IN:   array of handle
1414
   BYTE                *parmBufferStart,           //   IN:   start of parameter buffer
1415
   UINT32               parmBufferSize             //   IN:   size of parameter buffer
1416
   )
1417
8.48k
{
1418
8.48k
   UINT32 i;
1419
8.48k
   TPM_RC                result = TPM_RC_SUCCESS;
1420
   // Check if the commandCode requires authorization
1421
8.86k
   for(i = 0; i < handleNum; i++)
1422
388
   {
1423
388
       if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1424
6
           return TPM_RC_AUTH_MISSING;
1425
388
   }
1426
8.47k
#ifdef TPM_CC_GetCommandAuditDigest
1427
   // Check if the command should be audited.
1428
8.47k
   result = CheckCommandAudit(commandCode, handleNum, handles,
1429
8.47k
                              parmBufferStart, parmBufferSize);
1430
8.47k
   if(result != TPM_RC_SUCCESS) return result;
1431
8.47k
#endif
1432
   // Initialize number of sessions to be 0
1433
8.47k
   s_sessionNum = 0;
1434
8.47k
   return TPM_RC_SUCCESS;
1435
8.47k
}
1436
//
1437
//
1438
//            Response Session Processing
1439
//
1440
//            Introduction
1441
//
1442
//       The following functions build the session area in a response, and handle the audit sessions (if present).
1443
//
1444
//            ComputeRpHash()
1445
//
1446
//       Function to compute rpHash (Response Parameter Hash). The rpHash is only computed if there is an
1447
//       HMAC authorization session and the return code is TPM_RC_SUCCESS.
1448
//
1449
static void
1450
ComputeRpHash(
1451
   TPM_ALG_ID           hashAlg,                   //   IN: hash algorithm to compute rpHash
1452
   TPM_CC               commandCode,               //   IN: commandCode
1453
   UINT32               resParmBufferSize,         //   IN: size of response parameter buffer
1454
   BYTE                *resParmBuffer,             //   IN: response parameter buffer
1455
   TPM2B_DIGEST        *rpHash                     //   OUT: rpHash
1456
   )
1457
0
{
1458
   // The command result in rpHash is always TPM_RC_SUCCESS.
1459
0
   TPM_RC      responseCode = TPM_RC_SUCCESS;
1460
0
   HASH_STATE hashState;
1461
   //     rpHash := hash(responseCode || commandCode || parameters)
1462
    // Initiate hash creation.
1463
0
    rpHash->t.size = CryptStartHash(hashAlg, &hashState);
1464
    // Add hash constituents.
1465
0
    CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode);
1466
0
    CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
1467
0
    CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer);
1468
    // Complete hash computation.
1469
0
    CryptCompleteHash2B(&hashState, &rpHash->b);
1470
0
    return;
1471
0
}
1472
//
1473
//
1474
//             InitAuditSession()
1475
//
1476
//       This function initializes the audit data in an audit session.
1477
//
1478
static void
1479
InitAuditSession(
1480
    SESSION              *session             // session to be initialized
1481
    )
1482
0
{
1483
    // Mark session as an audit session.
1484
0
    session->attributes.isAudit = SET;
1485
    // Audit session can not be bound.
1486
0
    session->attributes.isBound = CLEAR;
1487
    // Size of the audit log is the size of session hash algorithm digest.
1488
0
    session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
1489
    // Set the original digest value to be 0.
1490
0
    MemorySet(&session->u2.auditDigest.t.buffer,
1491
0
              0,
1492
0
              session->u2.auditDigest.t.size);
1493
0
    return;
1494
0
}
1495
//
1496
//
1497
//             Audit()
1498
//
1499
//       This function updates the audit digest in an audit session.
1500
//
1501
static void
1502
Audit(
1503
    SESSION              *auditSession,            //   IN:    loaded audit session
1504
    TPM_CC                commandCode,             //   IN:    commandCode
1505
    UINT32                resParmBufferSize,       //   IN:    size of response parameter buffer
1506
    BYTE                 *resParmBuffer            //   IN:    response parameter buffer
1507
    )
1508
0
{
1509
0
    TPM2B_DIGEST          rpHash;                  // rpHash for response
1510
0
    HASH_STATE            hashState;
1511
    // Compute rpHash
1512
0
    ComputeRpHash(auditSession->authHashAlg,
1513
0
                  commandCode,
1514
0
                  resParmBufferSize,
1515
0
                  resParmBuffer,
1516
0
                  &rpHash);
1517
   // auditDigestnew :=      hash (auditDigestold || cpHash || rpHash)
1518
   // Start hash computation.
1519
0
   CryptStartHash(auditSession->authHashAlg, &hashState);
1520
   // Add old digest.
1521
0
   CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b);
1522
   // Add cpHash and rpHash.
1523
0
   CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b);
1524
0
   CryptUpdateDigest2B(&hashState, &rpHash.b);
1525
   // Finalize the hash.
1526
0
   CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b);
1527
0
   return;
1528
0
}
1529
#ifdef TPM_CC_GetCommandAuditDigest
1530
//
1531
//
1532
//            CommandAudit()
1533
//
1534
//       This function updates the command audit digest.
1535
//
1536
static void
1537
CommandAudit(
1538
   TPM_CC              commandCode,       // IN: commandCode
1539
   UINT32              resParmBufferSize, // IN: size of response parameter buffer
1540
   BYTE               *resParmBuffer      // IN: response parameter buffer
1541
   )
1542
6.77k
{
1543
6.77k
   if(CommandAuditIsRequired(commandCode))
1544
0
   {
1545
0
       TPM2B_DIGEST    rpHash;        // rpHash for response
1546
0
       HASH_STATE      hashState;
1547
         // Compute rpHash.
1548
0
         ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize,
1549
0
                       resParmBuffer, &rpHash);
1550
         // If the digest.size is one, it indicates the special case of changing
1551
         // the audit hash algorithm. For this case, no audit is done on exit.
1552
         // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1553
         // force an update to the NV on exit so that the change in digest will
1554
         // be recorded. So, it is safe to exit here without setting any flags
1555
         // because the digest change will be written to NV when this code exits.
1556
0
         if(gr.commandAuditDigest.t.size == 1)
1557
0
         {
1558
0
             gr.commandAuditDigest.t.size = 0;
1559
0
             return;
1560
0
         }
1561
         // If the digest size is zero, need to start a new digest and increment
1562
         // the audit counter.
1563
0
         if(gr.commandAuditDigest.t.size == 0)
1564
0
         {
1565
0
             gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg);
1566
0
             MemorySet(gr.commandAuditDigest.t.buffer,
1567
0
                       0,
1568
0
                       gr.commandAuditDigest.t.size);
1569
             // Bump the counter and save its value to NV.
1570
0
             gp.auditCounter++;
1571
0
             NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
1572
0
             g_updateNV = TRUE;
1573
//
1574
0
         }
1575
         // auditDigestnew :=         hash (auditDigestold || cpHash || rpHash)
1576
         // Start hash computation.
1577
0
         CryptStartHash(gp.auditHashAlg, &hashState);
1578
         // Add old digest.
1579
0
         CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b);
1580
         // Add cpHash
1581
0
         CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b);
1582
         // Add rpHash
1583
0
         CryptUpdateDigest2B(&hashState, &rpHash.b);
1584
         // Finalize the hash.
1585
0
         CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b);
1586
0
    }
1587
6.77k
    return;
1588
6.77k
}
1589
#endif
1590
//
1591
//
1592
//              UpdateAuditSessionStatus()
1593
//
1594
//       Function to update the internal audit related states of a session. It
1595
//       a) initializes the session as audit session and sets it to be exclusive if this is the first time it is used for
1596
//          audit or audit reset was requested;
1597
//       b) reports exclusive audit session;
1598
//       c) extends audit log; and
1599
//       d) clears exclusive audit session if no audit session found in the command.
1600
//
1601
static void
1602
UpdateAuditSessionStatus(
1603
    TPM_CC                commandCode,       // IN: commandCode
1604
    UINT32                resParmBufferSize, // IN: size of response parameter buffer
1605
    BYTE                 *resParmBuffer      // IN: response parameter buffer
1606
    )
1607
6.77k
{
1608
6.77k
    UINT32                i;
1609
6.77k
    TPM_HANDLE            auditSession = TPM_RH_UNASSIGNED;
1610
    // Iterate through sessions
1611
7.00k
    for (i = 0; i < s_sessionNum; i++)
1612
230
    {
1613
230
        SESSION     *session;
1614
         // PW session do not have a loaded session and can not be an audit
1615
         // session either. Skip it.
1616
230
         if(s_sessionHandles[i] == TPM_RS_PW) continue;
1617
0
         session = SessionGet(s_sessionHandles[i]);
1618
         // If a session is used for audit
1619
0
         if(s_attributes[i].audit == SET)
1620
0
         {
1621
             // An audit session has been found
1622
0
             auditSession = s_sessionHandles[i];
1623
              // If the session has not been an audit session yet, or
1624
              // the auditSetting bits indicate a reset, initialize it and set
1625
              // it to be the exclusive session
1626
0
              if(    session->attributes.isAudit == CLEAR
1627
0
                  || s_attributes[i].auditReset == SET
1628
0
                )
1629
0
              {
1630
0
                   InitAuditSession(session);
1631
0
                   g_exclusiveAuditSession = auditSession;
1632
0
              }
1633
0
              else
1634
0
              {
1635
                   // Check if the audit session is the current exclusive audit
1636
                   // session and, if not, clear previous exclusive audit session.
1637
0
                   if(g_exclusiveAuditSession != auditSession)
1638
0
                       g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1639
0
              }
1640
              // Report audit session exclusivity.
1641
0
              if(g_exclusiveAuditSession == auditSession)
1642
0
              {
1643
0
                  s_attributes[i].auditExclusive = SET;
1644
0
              }
1645
0
              else
1646
0
              {
1647
0
                  s_attributes[i].auditExclusive = CLEAR;
1648
0
              }
1649
              // Extend audit log.
1650
0
              Audit(session, commandCode, resParmBufferSize, resParmBuffer);
1651
0
         }
1652
0
   }
1653
   // If no audit session is found in the command, and the command allows
1654
   // a session then, clear the current exclusive
1655
   // audit session.
1656
6.77k
   if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode))
1657
1.13k
   {
1658
1.13k
       g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1659
1.13k
   }
1660
6.77k
   return;
1661
6.77k
}
1662
//
1663
//
1664
//              ComputeResponseHMAC()
1665
//
1666
//       Function to compute HMAC for authorization session in a response.
1667
//
1668
static void
1669
ComputeResponseHMAC(
1670
   UINT32              sessionIndex,         //   IN: session index to be processed
1671
   SESSION            *session,              //   IN: loaded session
1672
   TPM_CC              commandCode,          //   IN: commandCode
1673
   TPM2B_NONCE        *nonceTPM,             //   IN: nonceTPM
1674
   UINT32              resParmBufferSize,    //   IN: size of response parameter buffer
1675
   BYTE               *resParmBuffer,        //   IN: response parameter buffer
1676
   TPM2B_DIGEST       *hmac                  //   OUT: authHMAC
1677
   )
1678
0
{
1679
0
   TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1680
0
   TPM2B_KEY        key;       // HMAC key
1681
0
   BYTE             marshalBuffer[sizeof(TPMA_SESSION)];
1682
0
   BYTE            *buffer;
1683
0
   INT32            bufferSize;
1684
0
   UINT32           marshalSize;
1685
0
   HMAC_STATE       hmacState;
1686
0
   TPM2B_DIGEST     rp_hash;
1687
//
1688
   // Compute rpHash.
1689
0
   ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize,
1690
0
                 resParmBuffer, &rp_hash);
1691
   // Generate HMAC key
1692
0
   MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1693
   // Check if the session has an associated handle and the associated entity is
1694
   // the one that the session is bound to.
1695
   // If not bound, add the authValue of this entity to the HMAC key.
1696
0
   if(   s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED
1697
0
      &&    !( HandleGetType(s_sessionHandles[sessionIndex])
1698
0
                 == TPM_HT_POLICY_SESSION
1699
0
         &&   session->attributes.isAuthValueNeeded == CLEAR)
1700
0
      && !session->attributes.requestWasBound)
1701
0
   {
1702
0
       pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
1703
0
       key.t.size = key.t.size +
1704
0
                       EntityGetAuthValue(s_associatedHandles[sessionIndex],
1705
0
                                          (AUTH_VALUE *)&key.t.buffer[key.t.size]);
1706
0
   }
1707
   // if the HMAC key size for a policy session is 0, the response HMAC is
1708
   // computed according to the input HMAC
1709
0
   if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1710
0
       && key.t.size == 0
1711
0
       && s_inputAuthValues[sessionIndex].t.size == 0)
1712
0
   {
1713
0
       hmac->t.size = 0;
1714
0
       return;
1715
0
   }
1716
   // Start HMAC computation.
1717
0
   hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
1718
   // Add hash components.
1719
0
   CryptUpdateDigest2B(&hmacState, &rp_hash.b);
1720
0
   CryptUpdateDigest2B(&hmacState, &nonceTPM->b);
1721
0
   CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
1722
   // Add session attributes.
1723
0
   buffer = marshalBuffer;
1724
0
   bufferSize = sizeof(TPMA_SESSION);
1725
0
   marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, &bufferSize);
1726
0
   CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
1727
   // Finalize HMAC.
1728
0
   CryptCompleteHMAC2B(&hmacState, &hmac->b);
1729
0
   return;
1730
0
}
1731
//
1732
//
1733
//           BuildSingleResponseAuth()
1734
//
1735
//       Function to compute response for an authorization session.
1736
//
1737
static void
1738
BuildSingleResponseAuth(
1739
   UINT32              sessionIndex,          //   IN: session index to be processed
1740
   TPM_CC              commandCode,           //   IN: commandCode
1741
   UINT32              resParmBufferSize,     //   IN: size of response parameter buffer
1742
   BYTE               *resParmBuffer,         //   IN: response parameter buffer
1743
   TPM2B_AUTH         *auth                   //   OUT: authHMAC
1744
   )
1745
//
1746
230
{
1747
   // For password authorization, field is empty.
1748
230
   if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
1749
230
   {
1750
230
       auth->t.size = 0;
1751
230
   }
1752
0
   else
1753
0
   {
1754
       // Fill in policy/HMAC based session response.
1755
0
       SESSION     *session = SessionGet(s_sessionHandles[sessionIndex]);
1756
          // If the session is a policy session with isPasswordNeeded SET, the auth
1757
          // field is empty.
1758
0
          if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1759
0
                   && session->attributes.isPasswordNeeded == SET)
1760
0
               auth->t.size = 0;
1761
0
          else
1762
               // Compute response HMAC.
1763
0
               ComputeResponseHMAC(sessionIndex,
1764
0
                                   session,
1765
0
                                   commandCode,
1766
0
                                   &session->nonceTPM,
1767
0
                                   resParmBufferSize,
1768
0
                                   resParmBuffer,
1769
0
                                   auth);
1770
0
   }
1771
230
   return;
1772
230
}
1773
//
1774
//
1775
//            UpdateTPMNonce()
1776
//
1777
//       Updates TPM nonce in both internal session or response if applicable.
1778
//
1779
static void
1780
UpdateTPMNonce(
1781
   UINT16               noncesSize,       // IN: number of elements in 'nonces' array
1782
   TPM2B_NONCE          nonces[]          // OUT: nonceTPM
1783
   )
1784
230
{
1785
230
   UINT32      i;
1786
230
   pAssert(noncesSize >= s_sessionNum);
1787
460
   for(i = 0; i < s_sessionNum; i++)
1788
230
   {
1789
230
       SESSION     *session;
1790
       // For PW session, nonce is 0.
1791
230
       if(s_sessionHandles[i] == TPM_RS_PW)
1792
230
       {
1793
230
           nonces[i].t.size = 0;
1794
230
           continue;
1795
230
       }
1796
0
       session = SessionGet(s_sessionHandles[i]);
1797
       // Update nonceTPM in both internal session and response.
1798
0
       CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
1799
0
       nonces[i] = session->nonceTPM;
1800
0
   }
1801
230
   return;
1802
230
}
1803
//
1804
//
1805
//           UpdateInternalSession()
1806
//
1807
//       Updates internal sessions:
1808
//
1809
//
1810
//       a) Restarts session time, and
1811
//       b) Clears a policy session since nonce is rolling.
1812
//
1813
static void
1814
UpdateInternalSession(
1815
   void
1816
   )
1817
230
{
1818
230
   UINT32      i;
1819
460
   for(i = 0; i < s_sessionNum; i++)
1820
230
   {
1821
       // For PW session, no update.
1822
230
       if(s_sessionHandles[i] == TPM_RS_PW) continue;
1823
0
          if(s_attributes[i].continueSession == CLEAR)
1824
0
          {
1825
               // Close internal session.
1826
0
               SessionFlush(s_sessionHandles[i]);
1827
0
          }
1828
0
          else
1829
0
          {
1830
               // If nonce is rolling in a policy session, the policy related data
1831
               // will be re-initialized.
1832
0
               if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION)
1833
0
               {
1834
0
                   SESSION     *session = SessionGet(s_sessionHandles[i]);
1835
                   // When the nonce rolls it starts a new timing interval for the
1836
                   // policy session.
1837
0
                   SessionResetPolicyData(session);
1838
0
                   session->startTime = go.clock;
1839
0
               }
1840
0
          }
1841
0
   }
1842
230
   return;
1843
230
}
1844
//
1845
//
1846
//              BuildResponseSession()
1847
//
1848
//       Function to build Session buffer in a response.
1849
//
1850
void
1851
BuildResponseSession(
1852
   TPM_ST               tag,               //    IN: tag
1853
   TPM_CC               commandCode,       //    IN: commandCode
1854
   UINT32               resHandleSize,     //    IN: size of response handle buffer
1855
   UINT32               resParmSize,       //    IN: size of response parameter buffer
1856
   UINT32              *resSessionSize     //    OUT: response session area
1857
   )
1858
6.77k
{
1859
6.77k
   BYTE                *resParmBuffer;
1860
6.77k
   INT32                bufferSize;
1861
6.77k
   TPM2B_NONCE      responseNonces[MAX_SESSION_NUM];
1862
   // Compute response parameter buffer start.
1863
6.77k
   resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) +
1864
6.77k
                   sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize;
1865
6.77k
   bufferSize = MAX_RESPONSE_SIZE - sizeof(TPM_ST) - sizeof(UINT32) -
1866
6.77k
                sizeof(TPM_RC) - resHandleSize;
1867
   // For TPM_ST_SESSIONS, there is parameterSize field.
1868
6.77k
   if(tag == TPM_ST_SESSIONS) {
1869
230
       resParmBuffer += sizeof(UINT32);
1870
230
       bufferSize -= sizeof(UINT32);
1871
230
   }
1872
   // Session nonce should be updated before parameter encryption
1873
6.77k
   if(tag == TPM_ST_SESSIONS)
1874
230
   {
1875
230
         UpdateTPMNonce(MAX_SESSION_NUM, responseNonces);
1876
         // Encrypt first parameter if applicable. Parameter encryption should
1877
         // happen after nonce update and before any rpHash is computed.
1878
         // If the encrypt session is associated with a handle, the authValue of
1879
         // this handle will be concatenated with sessionAuth to generate
1880
         // encryption key, no matter if the handle is the session bound entity
1881
         // or not. The authValue is added to sessionAuth only when the authValue
1882
         // is available.
1883
230
         if(s_encryptSessionIndex != UNDEFINED_INDEX)
1884
0
         {
1885
0
             UINT32          size;
1886
0
             TPM2B_AUTH      extraKey;
1887
             // Get size of the leading size field
1888
0
             if(    s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED
1889
0
                 && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex],
1890
0
                                         commandCode, s_encryptSessionIndex)
1891
0
               )
1892
0
             {
1893
0
                  extraKey.b.size =
1894
0
                      EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
1895
0
                                         &extraKey.t.buffer);
1896
0
             }
1897
0
             else
1898
0
             {
1899
0
                  extraKey.b.size = 0;
1900
0
             }
1901
0
             size = EncryptSize(commandCode);
1902
0
             CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
1903
0
                                       &s_nonceCaller[s_encryptSessionIndex].b,
1904
0
                                       bufferSize,
1905
0
                                       (UINT16)size,
1906
0
                                       &extraKey,
1907
0
                                       resParmBuffer);
1908
0
         }
1909
230
   }
1910
   // Audit session should be updated first regardless of the tag.
1911
   // A command with no session may trigger a change of the exclusivity state.
1912
6.77k
   UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer);
1913
   // Audit command.
1914
6.77k
   CommandAudit(commandCode, resParmSize, resParmBuffer);
1915
   // Process command with sessions.
1916
6.77k
   if(tag == TPM_ST_SESSIONS)
1917
230
   {
1918
230
       UINT32           i;
1919
230
       BYTE            *buffer;
1920
230
       TPM2B_DIGEST     responseAuths[MAX_SESSION_NUM];
1921
230
         pAssert(s_sessionNum > 0);
1922
         // Iterate over each session in the command session area, and create
1923
         // corresponding sessions for response.
1924
460
         for(i = 0; i < s_sessionNum; i++)
1925
230
         {
1926
230
             BuildSingleResponseAuth(
1927
230
                                      i,
1928
230
                                      commandCode,
1929
230
                                      resParmSize,
1930
230
                                      resParmBuffer,
1931
230
                                      &responseAuths[i]);
1932
             // Make sure that continueSession is SET on any Password session.
1933
              // This makes it marginally easier for the management software
1934
              // to keep track of the closed sessions.
1935
230
              if(    s_attributes[i].continueSession == CLEAR
1936
230
                  && s_sessionHandles[i] == TPM_RS_PW)
1937
143
              {
1938
143
                   s_attributes[i].continueSession = SET;
1939
143
              }
1940
230
        }
1941
        // Assemble Response Sessions.
1942
230
        *resSessionSize = 0;
1943
230
        buffer = resParmBuffer + resParmSize;
1944
230
        bufferSize -= resParmSize;
1945
460
        for(i = 0; i < s_sessionNum; i++)
1946
230
        {
1947
230
            *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i],
1948
230
                                                   &buffer, &bufferSize);
1949
230
            *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i],
1950
230
                                                    &buffer, &bufferSize);
1951
230
            *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i],
1952
230
                                                    &buffer, &bufferSize);
1953
230
        }
1954
        // Update internal sessions after completing response buffer computation.
1955
230
        UpdateInternalSession();
1956
230
   }
1957
6.54k
   else
1958
6.54k
   {
1959
       // Process command with no session.
1960
6.54k
       *resSessionSize = 0;
1961
6.54k
   }
1962
6.77k
   return;
1963
6.77k
}