• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / libtpms / #2043

29 Dec 2025 06:12PM UTC coverage: 77.222% (-0.005%) from 77.227%
#2043

push

travis-ci

web-flow
Merge dad4446a5 into a3917cb92

36065 of 46703 relevant lines covered (77.22%)

101207.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.37
/src/tpm2/SessionProcess.c
1
/********************************************************************************/
2
/*                                                                                */
3
/*                Process the Authorization Sessions                                     */
4
/*                             Written by Ken Goldman                                */
5
/*                       IBM Thomas J. Watson Research Center                        */
6
/*                                                                                */
7
/*  Licenses and Notices                                                        */
8
/*                                                                                */
9
/*  1. Copyright Licenses:                                                        */
10
/*                                                                                */
11
/*  - Trusted Computing Group (TCG) grants to the user of the source code in        */
12
/*    this specification (the "Source Code") a worldwide, irrevocable,                 */
13
/*    nonexclusive, royalty free, copyright license to reproduce, create         */
14
/*    derivative works, distribute, display and perform the Source Code and        */
15
/*    derivative works thereof, and to grant others the rights granted herein.        */
16
/*                                                                                */
17
/*  - The TCG grants to the user of the other parts of the specification         */
18
/*    (other than the Source Code) the rights to reproduce, distribute,         */
19
/*    display, and perform the specification solely for the purpose of                 */
20
/*    developing products based on such documents.                                */
21
/*                                                                                */
22
/*  2. Source Code Distribution Conditions:                                        */
23
/*                                                                                */
24
/*  - Redistributions of Source Code must retain the above copyright licenses,         */
25
/*    this list of conditions and the following disclaimers.                        */
26
/*                                                                                */
27
/*  - Redistributions in binary form must reproduce the above copyright         */
28
/*    licenses, this list of conditions        and the following disclaimers in the         */
29
/*    documentation and/or other materials provided with the distribution.        */
30
/*                                                                                */
31
/*  3. Disclaimers:                                                                */
32
/*                                                                                */
33
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF        */
34
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH        */
35
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES)        */
36
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.                */
37
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for                 */
38
/*  information on specification licensing rights available through TCG         */
39
/*  membership agreements.                                                        */
40
/*                                                                                */
41
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED         */
42
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR         */
43
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR                 */
44
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY                 */
45
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.                */
46
/*                                                                                */
47
/*  - Without limitation, TCG and its members and licensors disclaim all         */
48
/*    liability, including liability for infringement of any proprietary         */
49
/*    rights, relating to use of information in this specification and to the        */
50
/*    implementation of this specification, and TCG disclaims all liability for        */
51
/*    cost of procurement of substitute goods or services, lost profits, loss         */
52
/*    of use, loss of data or any incidental, consequential, direct, indirect,         */
53
/*    or special damages, whether under contract, tort, warranty or otherwise,         */
54
/*    arising in any way out of use or reliance upon this specification or any         */
55
/*    information herein.                                                        */
56
/*                                                                                */
57
/*  (c) Copyright IBM Corp. and others, 2016 - 2023                                */
58
/*                                                                                */
59
/********************************************************************************/
60

61
//**  Introduction
62
// This file contains the subsystem that process the authorization sessions
63
// including implementation of the Dictionary Attack logic. ExecCommand() uses
64
// ParseSessionBuffer() to process the authorization session area of a command and
65
// BuildResponseSession() to create the authorization session area of a response.
66

67
//**  Includes and Data Definitions
68

69
#define SESSION_PROCESS_C
70

71
#include "Tpm.h"
72
#include "ACT.h"
73
#include "Marshal.h"
74

75
//
76
//**  Authorization Support Functions
77
//
78

79
//*** IsDAExempted()
80
// This function indicates if a handle is exempted from DA logic.
81
// A handle is exempted if it is:
82
//  a) a primary seed handle;
83
//  b) an object with noDA bit SET;
84
//  c) an NV Index with TPMA_NV_NO_DA bit SET; or
85
//  d) a PCR handle.
86
//
87
//  Return Type: BOOL
88
//      TRUE(1)         handle is exempted from DA logic
89
//      FALSE(0)        handle is not exempted from DA logic
90
BOOL IsDAExempted(TPM_HANDLE handle  // IN: entity handle
6,472✔
91
                  )
92
{
93
    BOOL result = FALSE;
6,472✔
94
    //
95
    switch(HandleGetType(handle))
6,472✔
96
        {
97
          case TPM_HT_PERMANENT:
3,638✔
98
            // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
99
            // DA protection.
100
            result = (handle != TPM_RH_LOCKOUT);
3,638✔
101
            break;
3,638✔
102
            // When this function is called, a persistent object will have been loaded
103
            // into an object slot and assigned a transient handle.
104
          case TPM_HT_TRANSIENT:
1,971✔
105
              {
106
                  TPMA_OBJECT attributes = ObjectGetPublicAttributes(handle);
1,971✔
107
                  result                 = IS_ATTRIBUTE(attributes, TPMA_OBJECT, noDA);
1,971✔
108
                  break;
1,971✔
109
              }
110
          case TPM_HT_NV_INDEX:
575✔
111
              {
112
                  NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
575✔
113
                  result = IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, NO_DA);
575✔
114
                  break;
575✔
115
              }
116
          case TPM_HT_PCR:
288✔
117
            // PCRs are always exempted from DA.
118
            result = TRUE;
288✔
119
            break;
288✔
120
          default:
121
            break;
122
        }
123
    return result;
6,472✔
124
}
125

126
//*** IncrementLockout()
127
// This function is called after an authorization failure that involves use of
128
// an authValue. If the entity referenced by the handle is not exempt from DA
129
// protection, then the failedTries counter will be incremented.
130
//
131
//  Return Type: TPM_RC
132
//      TPM_RC_AUTH_FAIL    authorization failure that caused DA lockout to increment
133
//      TPM_RC_BAD_AUTH     authorization failure did not cause DA lockout to
134
//                          increment
135
static TPM_RC IncrementLockout(UINT32 sessionIndex)
89✔
136
{
137
    TPM_HANDLE handle        = s_associatedHandles[sessionIndex];
89✔
138
    TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
89✔
139
    SESSION*   session       = NULL;
89✔
140
    //
141
    // Don't increment lockout unless the handle associated with the session
142
    // is DA protected or the session is bound to a DA protected entity.
143
    if(sessionHandle == TPM_RS_PW)
89✔
144
        {
145
            if(IsDAExempted(handle))
78✔
146
                return TPM_RC_BAD_AUTH;
147
        }
148
    else
149
        {
150
            session = SessionGet(sessionHandle);
11✔
151
            // If the session is bound to lockout, then use that as the relevant
152
            // handle. This means that an authorization failure with a bound session
153
            // bound to lockoutAuth will take precedence over any other
154
            // lockout check
155
            if(session->attributes.isLockoutBound == SET)
11✔
156
                handle = TPM_RH_LOCKOUT;
×
157
            if(session->attributes.isDaBound == CLEAR
11✔
158
               && (IsDAExempted(handle) || session->attributes.includeAuth == CLEAR))
11✔
159
                // If the handle was changed to TPM_RH_LOCKOUT, this will not return
160
                // TPM_RC_BAD_AUTH
161
                return TPM_RC_BAD_AUTH;
162
        }
163
    if(handle == TPM_RH_LOCKOUT)
20✔
164
        {
165
            pAssert(gp.lockOutAuthEnabled == TRUE);
4✔
166

167
            // lockout is no longer enabled
168
            gp.lockOutAuthEnabled = FALSE;
4✔
169

170
            // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
171
            // the lockout authorization will be reset at startup.
172
            if(gp.lockoutRecovery != 0)
4✔
173
                {
174
                    if(NV_IS_AVAILABLE)
4✔
175
                        // Update NV.
176
                        NV_SYNC_PERSISTENT(lockOutAuthEnabled);
4✔
177
                    else
178
                        // No NV access for now. Put the TPM in pending mode.
179
                        s_DAPendingOnNV = TRUE;
×
180
                }
181
        }
182
    else
183
        {
184
            if(gp.recoveryTime != 0)
16✔
185
                {
186
                    gp.failedTries++;
15✔
187
                    if(NV_IS_AVAILABLE)
15✔
188
                        // Record changes to NV. NvWrite will SET g_updateNV
189
                        NV_SYNC_PERSISTENT(failedTries);
15✔
190
                    else
191
                        // No NV access for now.  Put the TPM in pending mode.
192
                        s_DAPendingOnNV = TRUE;
×
193
                }
194
        }
195
    // Register a DA failure and reset the timers.
196
    DARegisterFailure(handle);
20✔
197

198
    return TPM_RC_AUTH_FAIL;
20✔
199
}
200

201
//*** IsSessionBindEntity()
202
// This function indicates if the entity associated with the handle is the entity,
203
// to which this session is bound. The binding would occur by making the "bind"
204
// parameter in TPM2_StartAuthSession() not equal to TPM_RH_NULL. The binding only
205
// occurs if the session is an HMAC session. The bind value is a combination of
206
// the Name and the authValue of the entity.
207
//
208
//  Return Type: BOOL
209
//      TRUE(1)         handle points to the session start entity
210
//      FALSE(0)        handle does not point to the session start entity
211
static BOOL IsSessionBindEntity(
772✔
212
                                TPM_HANDLE associatedHandle,  // IN: handle to be authorized
213
                                SESSION*   session            // IN: associated session
214
                                )
215
{
216
    TPM2B_NAME entity;  // The bind value for the entity
772✔
217
    //
218
    // If the session is not bound, return FALSE.
219
    if(session->attributes.isBound)
772✔
220
        {
221
            // Compute the bind value for the entity.
222
            SessionComputeBoundEntity(associatedHandle, &entity);
60✔
223

224
            // Compare to the bind value in the session.
225
            return MemoryEqual2B(&entity.b, &session->u1.boundEntity.b);
60✔
226
        }
227
    return FALSE;
228
}
229

230
//*** IsPolicySessionRequired()
231
// Checks if a policy session is required for a command. If a command requires
232
// DUP or ADMIN role authorization, then the handle that requires that role is the
233
// first handle in the command. This simplifies this checking. If a new command
234
// is created that requires multiple ADMIN role authorizations, then it will
235
// have to be special-cased in this function.
236
// A policy session is required if:
237
// a) the command requires the DUP role;
238
// b) the command requires the ADMIN role and the authorized entity
239
//    is an object and its adminWithPolicy bit is SET;
240
// c) the command requires the ADMIN role and the authorized entity
241
//    is a permanent handle or an NV Index; or
242
// d) the authorized entity is a PCR belonging to a policy group, and
243
//    has its policy initialized
244
//  Return Type: BOOL
245
//      TRUE(1)         policy session is required
246
//      FALSE(0)        policy session is not required
247
static BOOL IsPolicySessionRequired(COMMAND_INDEX commandIndex,  // IN: command index
6,348✔
248
                                    UINT32        sessionIndex   // IN: session index
249
                                    )
250
{
251
    AUTH_ROLE role = CommandAuthRole(commandIndex, sessionIndex);
6,348✔
252
    TPM_HT    type = HandleGetType(s_associatedHandles[sessionIndex]);
6,348✔
253
    //
254
    if(role == AUTH_DUP)
6,348✔
255
        return TRUE;
256
    if(role == AUTH_ADMIN)
6,348✔
257
        {
258
            // We allow an exception for ADMIN role in a transient object. If the object
259
            // allows ADMIN role actions with authorization, then policy is not
260
            // required. For all other cases, there is no way to override the command
261
            // requirement that a policy be used
262
            if(type == TPM_HT_TRANSIENT)
284✔
263
                {
264
                    OBJECT* object = HandleToObject(s_associatedHandles[sessionIndex]);
271✔
265

266
                    if(!IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy))
271✔
267
                        return FALSE;
268
                }
269
            return TRUE;
13✔
270
        }
271

272
    if(type == TPM_HT_PCR)
6,064✔
273
        {
274
            if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex]))
276✔
275
                {
276
                    TPM2B_DIGEST  policy;
×
277
                    TPMI_ALG_HASH policyAlg;
×
278
                    policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], &policy);
×
279
                    if(policyAlg != TPM_ALG_NULL)
×
280
                        return TRUE;
×
281
                }
282
        }
283
    return FALSE;
284
}
285

286
//*** IsAuthValueAvailable()
287
// This function indicates if authValue is available and allowed for USER role
288
// authorization of an entity.
289
//
290
// This function is similar to IsAuthPolicyAvailable() except that it does not
291
// check the size of the authValue as IsAuthPolicyAvailable() does (a null
292
// authValue is a valid authorization, but a null policy is not a valid policy).
293
//
294
// This function does not check that the handle reference is valid or if the entity
295
// is in an enabled hierarchy. Those checks are assumed to have been performed
296
// during the handle unmarshaling.
297
//
298
//  Return Type: BOOL
299
//      TRUE(1)         authValue is available
300
//      FALSE(0)        authValue is not available
301
static BOOL IsAuthValueAvailable(TPM_HANDLE    handle,        // IN: handle of entity
6,308✔
302
                                 COMMAND_INDEX commandIndex,  // IN: command index
303
                                 UINT32        sessionIndex   // IN: session index
304
                                 )
305
{
306
    BOOL result = FALSE;
6,308✔
307
    //
308
    switch(HandleGetType(handle))
6,308✔
309
        {
310
          case TPM_HT_PERMANENT:
3,565✔
311
            switch(handle)
3,565✔
312
                {
313
                    // At this point hierarchy availability has already been
314
                    // checked so primary seed handles are always available here
315
                  case TPM_RH_OWNER:
3,565✔
316
                  case TPM_RH_ENDORSEMENT:
317
                  case TPM_RH_PLATFORM:
318
#if VENDOR_PERMANENT_AUTH_ENABLED == YES
319
                    // This vendor defined handle associated with the
320
                    // manufacturer's shared secret
321
                  case VENDOR_PERMANENT_AUTH_HANDLE:
322
#endif
323
                    // The DA checking has been performed on LockoutAuth but we
324
                    // bypass the DA logic if we are using lockout policy. The
325
                    // policy would allow execution to continue an lockoutAuth
326
                    // could be used, even if direct use of lockoutAuth is disabled
327
                  case TPM_RH_LOCKOUT:
328
                    // NullAuth is always available.
329
                  case TPM_RH_NULL:
330
                    result = TRUE;
3,565✔
331
                    break;
3,565✔
332

333
#ifndef __ACT_DISABLED        // libtpms changed
334
                    FOR_EACH_ACT(CASE_ACT_HANDLE)
335
                        {
336
                            // The ACT auth value is not available if the platform is disabled
337
                            result = g_phEnable == SET;
338
                            break;
339
                        }
340
#endif  // ACT_SUPPORT
341

342
                  default:
343
                    // Otherwise authValue is not available.
344
                    break;
345
                }
346
            break;
347
          case TPM_HT_TRANSIENT:
1,960✔
348
            // A persistent object has already been loaded and the internal
349
            // handle changed.
350
              {
351
                  OBJECT*     object;
1,960✔
352
                  TPMA_OBJECT attributes;
1,960✔
353
                  //
354
                  object     = HandleToObject(handle);
1,960✔
355
                  attributes = object->publicArea.objectAttributes;
1,960✔
356

357
                  // authValue is always available for a sequence object.
358
                  // An alternative for this is to
359
                  // SET_ATTRIBUTE(object->publicArea, TPMA_OBJECT, userWithAuth) when the
360
                  // sequence is started.
361
                  if(ObjectIsSequence(object))
1,960✔
362
                      {
363
                          result = TRUE;
364
                          break;
365
                      }
366
                  // authValue is available for an object if it has its sensitive
367
                  // portion loaded and
368
                  //  a) userWithAuth bit is SET, or
369
                  //  b) ADMIN role is required
370
                  if(object->attributes.publicOnly == CLEAR
1,851✔
371
                     && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, userWithAuth)
1,851✔
372
                         || (CommandAuthRole(commandIndex, sessionIndex) == AUTH_ADMIN
8✔
373
                             && !IS_ATTRIBUTE(
×
374
                                              attributes, TPMA_OBJECT, adminWithPolicy))))
375
                      result = TRUE;
376
              }
377
              break;
378
          case TPM_HT_NV_INDEX:
507✔
379
            // NV Index.
380
              {
381
                  NV_REF    locator;
507✔
382
                  NV_INDEX* nvIndex = NvGetIndexInfo(handle, &locator);
507✔
383
                  TPMA_NV   nvAttributes;
507✔
384
                  //
385
                  pAssert(nvIndex != 0);
507✔
386

387
                  nvAttributes = nvIndex->publicArea.attributes;
507✔
388

389
                  if(IsWriteOperation(commandIndex))
507✔
390
                      {
391
                          // AuthWrite can't be set for a PIN index
392
                          if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHWRITE))
225✔
393
                              result = TRUE;
221✔
394
                      }
395
                  else
396
                      {
397
                          // A "read" operation
398
                          // For a PIN Index, the authValue is available as long as the
399
                          // Index has been written and the pinCount is less than pinLimit
400
                          if(IsNvPinFailIndex(nvAttributes)
282✔
401
                             || IsNvPinPassIndex(nvAttributes))
282✔
402
                              {
403
                                  NV_PIN pin;
32✔
404
                                  if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
32✔
405
                                      break;  // return false
406
                                  // get the index values
407
                                  pin.intVal = NvGetUINT64Data(nvIndex, locator);
31✔
408
                                  if(pin.pin.pinCount < pin.pin.pinLimit)
31✔
409
                                      result = TRUE;
21✔
410
                              }
411
                          // For non-PIN Indexes, need to allow use of the authValue
412
                          else if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHREAD))
250✔
413
                              result = TRUE;
246✔
414
                      }
415
              }
416
              break;
506✔
417
          case TPM_HT_PCR:
276✔
418
            // PCR handle.
419
            // authValue is always allowed for PCR
420
            result = TRUE;
276✔
421
            break;
276✔
422
          default:
423
            // Otherwise, authValue is not available
424
            break;
425
        }
426
    return result;
6,308✔
427
}
428

429
//*** IsAuthPolicyAvailable()
430
// This function indicates if an authPolicy is available and allowed.
431
//
432
// This function does not check that the handle reference is valid or if the entity
433
// is in an enabled hierarchy. Those checks are assumed to have been performed
434
// during the handle unmarshaling.
435
//
436
//  Return Type: BOOL
437
//      TRUE(1)         authPolicy is available
438
//      FALSE(0)        authPolicy is not available
439
static BOOL IsAuthPolicyAvailable(TPM_HANDLE    handle,        // IN: handle of entity
208✔
440
                                  COMMAND_INDEX commandIndex,  // IN: command index
441
                                  UINT32        sessionIndex   // IN: session index
442
                                  )
443
{
444
    BOOL result = FALSE;
208✔
445
    //
446
    switch(HandleGetType(handle))
208✔
447
        {
448
          case TPM_HT_PERMANENT:
7✔
449
            switch(handle)
7✔
450
                {
451
                    // At this point hierarchy availability has already been checked.
452
                  case TPM_RH_OWNER:
×
453
                    if(gp.ownerPolicy.t.size != 0)
×
454
                        result = TRUE;
×
455
                    break;
456
                  case TPM_RH_ENDORSEMENT:
×
457
                    if(gp.endorsementPolicy.t.size != 0)
×
458
                        result = TRUE;
×
459
                    break;
460
                  case TPM_RH_PLATFORM:
7✔
461
                    if(gc.platformPolicy.t.size != 0)
7✔
462
                        result = TRUE;
7✔
463
                    break;
464
#if ACT_SUPPORT || 1        // libtpms changed
465

466
#  define ACT_GET_POLICY(N)                                                \
467
                    case TPM_RH_ACT_##N:                                \
468
                      if(go.ACT_##N.authPolicy.t.size != 0)                \
469
                          result = TRUE;                                \
470
                      break;
471

472
                    FOR_EACH_ACT(ACT_GET_POLICY)
473
#endif  // ACT_SUPPORT
474

475
                  case TPM_RH_LOCKOUT:
×
476
                    if(gp.lockoutPolicy.t.size != 0)
×
477
                        result = TRUE;
×
478
                    break;
479
                  default:
480
                    break;
481
                }
482
            break;
483
          case TPM_HT_TRANSIENT:
163✔
484
              {
485
                  // Object handle.
486
                  // An evict object would already have been loaded and given a
487
                  // transient object handle by this point.
488
                  OBJECT* object = HandleToObject(handle);
163✔
489
                  // Policy authorization is not available for an object with only
490
                  // public portion loaded.
491
                  if(object->attributes.publicOnly == CLEAR)
163✔
492
                      {
493
                          // Policy authorization is always available for an object but
494
                          // is never available for a sequence.
495
                          if(!ObjectIsSequence(object))
163✔
496
                              result = TRUE;
163✔
497
                      }
498
                  break;
499
              }
500
          case TPM_HT_NV_INDEX:
38✔
501
            // An NV Index.
502
              {
503
                  NV_INDEX* nvIndex      = NvGetIndexInfo(handle, NULL);
38✔
504
                  TPMA_NV   nvAttributes = nvIndex->publicArea.attributes;
38✔
505
                  //
506
                  // If the policy size is not zero, check if policy can be used.
507
                  if(nvIndex->publicArea.authPolicy.t.size != 0)
38✔
508
                      {
509
                          // If policy session is required for this handle, always
510
                          // uses policy regardless of the attributes bit setting
511
                          if(IsPolicySessionRequired(commandIndex, sessionIndex))
38✔
512
                              result = TRUE;
513
                          // Otherwise, the presence of the policy depends on the NV
514
                          // attributes.
515
                          else if(IsWriteOperation(commandIndex))
27✔
516
                              {
517
                                  if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYWRITE))
19✔
518
                                      result = TRUE;
19✔
519
                              }
520
                          else
521
                              {
522
                                  if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYREAD))
8✔
523
                                      result = TRUE;
8✔
524
                              }
525
                      }
526
              }
527
              break;
528
          case TPM_HT_PCR:
×
529
            // PCR handle.
530
            if(PCRPolicyIsAvailable(handle))
×
531
                result = TRUE;
×
532
            break;
533
          default:
534
            break;
535
        }
536
    return result;
208✔
537
}
538

539
//**  Session Parsing Functions
540

541
//*** ClearCpRpHashes()
542
void ClearCpRpHashes(COMMAND* command)
16,724✔
543
{
544
    // The macros expand according to the implemented hash algorithms. An IDE may
545
    // complain that COMMAND does not contain SHA1CpHash or SHA1RpHash because of the
546
    // complexity of the macro expansion where the data space is defined; but, if SHA1
547
    // is implemented, it actually does  and the compiler is happy.
548
#define CLEAR_CP_HASH(HASH, Hash) command->Hash##CpHash.b.size = 0;
549
    FOR_EACH_HASH(CLEAR_CP_HASH)
16,724✔
550
#define CLEAR_RP_HASH(HASH, Hash) command->Hash##RpHash.b.size = 0;
551
        FOR_EACH_HASH(CLEAR_RP_HASH)
16,724✔
552
        }
16,724✔
553

554
//*** GetCpHashPointer()
555
// Function to get a pointer to the cpHash of the command
556
static TPM2B_DIGEST* GetCpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,055✔
557
{
558
    TPM2B_DIGEST* retVal;
1,055✔
559
    //
560
    // Define the macro that will expand for each implemented algorithm in the switch
561
    // statement below.
562
#define GET_CP_HASH_POINTER(HASH, Hash)                                    \
563
    case ALG_##HASH##_VALUE:                                            \
564
      retVal = (TPM2B_DIGEST*)&command->Hash##CpHash;                    \
565
      break;
566

567
    switch(hashAlg)
1,055✔
568
        {
569
            // For each implemented hash, this will expand as defined above
570
            // by GET_CP_HASH_POINTER. Your IDE may complain that
571
            // 'struct "COMMAND" has no field "SHA1CpHash"' but the compiler says
572
            // it does, so...
573
            FOR_EACH_HASH(GET_CP_HASH_POINTER)
1,055✔
574
          default:
575
            retVal = NULL;
576
            break;
577
        }
578
    return retVal;
1,055✔
579
}
580

581
//*** GetRpHashPointer()
582
// Function to get a pointer to the RpHash of the command
583
static TPM2B_DIGEST* GetRpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,026✔
584
{
585
    TPM2B_DIGEST* retVal;
1,026✔
586
    //
587
    // Define the macro that will expand for each implemented algorithm in the switch
588
    // statement below.
589
#define GET_RP_HASH_POINTER(HASH, Hash)                                    \
590
    case ALG_##HASH##_VALUE:                                            \
591
      retVal = (TPM2B_DIGEST*)&command->Hash##RpHash;                    \
592
      break;
593

594
    switch(hashAlg)
1,026✔
595
        {
596
            // For each implemented hash, this will expand as defined above
597
            // by GET_RP_HASH_POINTER. Your IDE may complain that
598
            // 'struct "COMMAND" has no field 'SHA1RpHash'" but the compiler says
599
            // it does, so...
600
            FOR_EACH_HASH(GET_RP_HASH_POINTER)
1,026✔
601
          default:
602
            retVal = NULL;
603
            break;
604
        }
605
    return retVal;
1,026✔
606
}
607

608
//*** ComputeCpHash()
609
// This function computes the cpHash as defined in Part 2 and described in Part 1.
610
static TPM2B_DIGEST* ComputeCpHash(COMMAND* command,  // IN: command parsing structure
1,003✔
611
                                   TPMI_ALG_HASH hashAlg  // IN: hash algorithm
612
                                   )
613
{
614
    UINT32        i;
1,003✔
615
    HASH_STATE    hashState;
1,003✔
616
    TPM2B_NAME    name;
1,003✔
617
    TPM2B_DIGEST* cpHash;
1,003✔
618
    //
619
    // cpHash = hash(commandCode [ || authName1
620
    //                           [ || authName2
621
    //                           [ || authName 3 ]]]
622
    //                           [ || parameters])
623
    // A cpHash can contain just a commandCode only if the lone session is
624
    // an audit session.
625
    // Get pointer to the hash value
626
    cpHash = GetCpHashPointer(command, hashAlg);
1,003✔
627
    if(cpHash->t.size == 0)
1,003✔
628
        {
629
            cpHash->t.size = CryptHashStart(&hashState, hashAlg);
726✔
630
            //  Add commandCode.
631
            CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
726✔
632
            //  Add authNames for each of the handles.
633
            for(i = 0; i < command->handleNum; i++)
2,553✔
634
                CryptDigestUpdate2B(&hashState,
2,202✔
635
                                    &EntityGetName(command->handles[i], &name)->b);
1,101✔
636
            //  Add the parameters.
637
            CryptDigestUpdate(
726✔
638
                              &hashState, command->parameterSize, command->parameterBuffer);
726✔
639
            //  Complete the hash.
640
            CryptHashEnd2B(&hashState, &cpHash->b);
726✔
641
        }
642
    return cpHash;
1,003✔
643
}
644

645
//*** GetCpHash()
646
// This function is used to access a precomputed cpHash.
647
static TPM2B_DIGEST* GetCpHash(COMMAND* command, TPMI_ALG_HASH hashAlg)
52✔
648
{
649
    TPM2B_DIGEST* cpHash = GetCpHashPointer(command, hashAlg);
52✔
650
    //
651
    pAssert(cpHash->t.size != 0);
52✔
652
    return cpHash;
52✔
653
}
654

655
//*** CompareTemplateHash()
656
// This function computes the template hash and compares it to the session
657
// templateHash. It is the hash of the second parameter
658
// assuming that the command is TPM2_Create(), TPM2_CreatePrimary(), or
659
// TPM2_CreateLoaded()
660
//  Return Type: BOOL
661
//      TRUE(1)         template hash equal to session->templateHash
662
//      FALSE(0)        template hash not equal to session->templateHash
663
static BOOL CompareTemplateHash(COMMAND* command,  // IN: parsing structure
3✔
664
                                SESSION* session   // IN: session data
665
                                )
666
{
667
    BYTE*        pBuffer = command->parameterBuffer;
3✔
668
    INT32        pSize   = command->parameterSize;
3✔
669
    TPM2B_DIGEST tHash;
3✔
670
    UINT16       size;
3✔
671
    //
672
    // Only try this for the three commands for which it is intended
673
    if(command->code != TPM_CC_Create && command->code != TPM_CC_CreatePrimary
3✔
674
#if CC_CreateLoaded
675
       && command->code != TPM_CC_CreateLoaded
1✔
676
#endif
677
       )
678
        return FALSE;
679
    // Assume that the first parameter is a TPM2B and unmarshal the size field
680
    // Note: this will not affect the parameter buffer and size in the calling
681
    // function.
682
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
683
        return FALSE;
684
    // reduce the space in the buffer.
685
    // NOTE: this could make pSize go negative if the parameters are not correct but
686
    // the unmarshaling code does not try to unmarshal if the remaining size is
687
    // negative.
688
    pSize -= size;
3✔
689

690
    // Advance the pointer
691
    pBuffer += size;
3✔
692

693
    // Get the size of what should be the template
694
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
695
        return FALSE;
696
    // See if this is reasonable
697
    if(size > pSize)
3✔
698
        return FALSE;
699
    // Hash the template data
700
    tHash.t.size = CryptHashBlock(
6✔
701
                                  session->authHashAlg, size, pBuffer, sizeof(tHash.t.buffer), tHash.t.buffer);
3✔
702
    return (MemoryEqual2B(&session->u1.templateHash.b, &tHash.b));
3✔
703
}
704

705
//*** CompareNameHash()
706
// This function computes the name hash and compares it to the nameHash in the
707
// session data, returning true if they are equal.
708
BOOL CompareNameHash(COMMAND* command,  // IN: main parsing structure
3✔
709
                     SESSION* session   // IN: session structure with nameHash
710
                     )
711
{
712
    HASH_STATE   hashState;
3✔
713
    TPM2B_DIGEST nameHash;
3✔
714
    UINT32       i;
3✔
715
    TPM2B_NAME   name;
3✔
716
    //
717
    nameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
718
    //  Add names.
719
    for(i = 0; i < command->handleNum; i++)
8✔
720
        CryptDigestUpdate2B(&hashState,
10✔
721
                            &EntityGetName(command->handles[i], &name)->b);
5✔
722
    //  Complete hash.
723
    CryptHashEnd2B(&hashState, &nameHash.b);
3✔
724
    // and compare
725
    return MemoryEqual(
6✔
726
                       session->u1.nameHash.t.buffer, nameHash.t.buffer, nameHash.t.size);
3✔
727
}
728

729
//*** CompareParametersHash()
730
// This function computes the parameters hash and compares it to the pHash in
731
// the session data, returning true if they are equal.
732
BOOL CompareParametersHash(COMMAND* command,  // IN: main parsing structure
3✔
733
                           SESSION* session   // IN: session structure with pHash
734
                           )
735
{
736
    HASH_STATE   hashState;
3✔
737
    TPM2B_DIGEST pHash;
3✔
738
    //
739
    pHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
740
    //  Add commandCode.
741
    CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
3✔
742
    //  Add the parameters.
743
    CryptDigestUpdate(&hashState, command->parameterSize, command->parameterBuffer);
3✔
744
    //  Complete hash.
745
    CryptHashEnd2B(&hashState, &pHash.b);
3✔
746
    // and compare
747
    return MemoryEqual2B(&session->u1.pHash.b, &pHash.b);
3✔
748
}
749

750
//*** CheckPWAuthSession()
751
// This function validates the authorization provided in a PWAP session. It
752
// compares the input value to authValue of the authorized entity. Argument
753
// sessionIndex is used to get handles handle of the referenced entities from
754
// s_inputAuthValues[] and s_associatedHandles[].
755
//
756
//  Return Type: TPM_RC
757
//        TPM_RC_AUTH_FAIL          authorization fails and increments DA failure
758
//                                  count
759
//        TPM_RC_BAD_AUTH           authorization fails but DA does not apply
760
//
761
static TPM_RC CheckPWAuthSession(
5,519✔
762
                                 UINT32 sessionIndex  // IN: index of session to be processed
763
                                 )
764
{
765
    TPM2B_AUTH authValue;
5,519✔
766
    TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex];
5,519✔
767
    //
768
    // Strip trailing zeros from the password.
769
    MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]);
5,519✔
770

771
    // Get the authValue with trailing zeros removed
772
    EntityGetAuthValue(associatedHandle, &authValue);
5,519✔
773

774
    // Success if the values are identical.
775
    if(MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &authValue.b))
5,519✔
776
        {
777
            return TPM_RC_SUCCESS;
778
        }
779
    else  // if the digests are not identical
780
        {
781
            // Invoke DA protection if applicable.
782
            return IncrementLockout(sessionIndex);
79✔
783
        }
784
}
785

786
//*** ComputeCommandHMAC()
787
// This function computes the HMAC for an authorization session in a command.
788
/*(See part 1 specification -- this tag keeps this comment from showing up in
789
// merged document which is probably good because this comment doesn't look right.
790
//      The sessionAuth value
791
//      authHMAC := HMACsHash((sessionKey | authValue),
792
//                  (pHash | nonceNewer | nonceOlder  | nonceTPMencrypt-only
793
//                   | nonceTPMaudit   | sessionAttributes))
794
// Where:
795
//      HMACsHash()     The HMAC algorithm using the hash algorithm specified
796
//                      when the session was started.
797
//
798
//      sessionKey      A value that is computed in a protocol-dependent way,
799
//                      using KDFa. When used in an HMAC or KDF, the size field
800
//                      for this value is not included.
801
//
802
//      authValue       A value that is found in the sensitive area of an entity.
803
//                      When used in an HMAC or KDF, the size field for this
804
//                      value is not included.
805
//
806
//      pHash           Hash of the command (cpHash) using the session hash.
807
//                      When using a pHash in an HMAC computation, only the
808
//                      digest is used.
809
//
810
//      nonceNewer      A value that is generated by the entity using the
811
//                      session. A new nonce is generated on each use of the
812
//                      session. For a command, this will be nonceCaller.
813
//                      When used in an HMAC or KDF, the size field is not used.
814
//
815
//      nonceOlder      A TPM2B_NONCE that was received the previous time the
816
//                      session was used. For a command, this is nonceTPM.
817
//                      When used in an HMAC or KDF, the size field is not used.
818
//
819
//      nonceTPMdecrypt     The nonceTPM of the decrypt session is included in
820
//                          the HMAC, but only in the command.
821
//
822
//      nonceTPMencrypt     The nonceTPM of the encrypt session is included in
823
//                          the HMAC but only in the command.
824
//
825
//      sessionAttributes   A byte indicating the attributes associated with the
826
//                          particular use of the session.
827
*/
828
static TPM2B_DIGEST* ComputeCommandHMAC(
1,028✔
829
                                        COMMAND*      command,       // IN: primary control structure
830
                                        UINT32        sessionIndex,  // IN: index of session to be processed
831
                                        TPM2B_DIGEST* hmac           // OUT: authorization HMAC
832
                                        )
833
{
834
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1,028✔
835
    TPM2B_KEY    key;
1,028✔
836
    BYTE         marshalBuffer[sizeof(TPMA_SESSION)];
1,028✔
837
    BYTE*        buffer;
1,028✔
838
    UINT32       marshalSize;
1,028✔
839
    HMAC_STATE   hmacState;
1,028✔
840
    TPM2B_NONCE* nonceDecrypt;
1,028✔
841
    TPM2B_NONCE* nonceEncrypt;
1,028✔
842
    SESSION*     session;
1,028✔
843
    //
844
    nonceDecrypt = NULL;
1,028✔
845
    nonceEncrypt = NULL;
1,028✔
846

847
    // Determine if extra nonceTPM values are going to be required.
848
    // If this is the first session (sessionIndex = 0) and it is an authorization
849
    // session that uses an HMAC, then check if additional session nonces are to be
850
    // included.
851
    if(sessionIndex == 0 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
1,028✔
852
        {
853
            // If there is a decrypt session and if this is not the decrypt session,
854
            // then an extra nonce may be needed.
855
            if(s_decryptSessionIndex != UNDEFINED_INDEX
773✔
856
               && s_decryptSessionIndex != sessionIndex)
160✔
857
                {
858
                    // Will add the nonce for the decrypt session.
859
                    SESSION* decryptSession =
84✔
860
                        SessionGet(s_sessionHandles[s_decryptSessionIndex]);
84✔
861
                    nonceDecrypt = &decryptSession->nonceTPM;
84✔
862
                }
863
            // Now repeat for the encrypt session.
864
            if(s_encryptSessionIndex != UNDEFINED_INDEX
773✔
865
               && s_encryptSessionIndex != sessionIndex
152✔
866
               && s_encryptSessionIndex != s_decryptSessionIndex)
84✔
867
                {
868
                    // Have to have the nonce for the encrypt session.
869
                    SESSION* encryptSession =
64✔
870
                        SessionGet(s_sessionHandles[s_encryptSessionIndex]);
64✔
871
                    nonceEncrypt = &encryptSession->nonceTPM;
64✔
872
                }
873
        }
874

875
    // Continue with the HMAC processing.
876
    session = SessionGet(s_sessionHandles[sessionIndex]);
1,028✔
877

878
    // Generate HMAC key.
879
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1,028✔
880

881
    // Check if the session has an associated handle and if the associated entity
882
    // is the one to which the session is bound. If not, add the authValue of
883
    // this entity to the HMAC key.
884
    // If the session is bound to the object or the session is a policy session
885
    // with no authValue required, do not include the authValue in the HMAC key.
886
    // Note: For a policy session, its isBound attribute is CLEARED.
887
    //
888
    // Include the entity authValue if it is needed
889
    if(session->attributes.includeAuth == SET)
1,028✔
890
        {
891
            TPM2B_AUTH authValue;
735✔
892
            // Get the entity authValue with trailing zeros removed
893
            EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
735✔
894
            // add the authValue to the HMAC key
895
            MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
735✔
896
        }
897
    // if the HMAC key size is 0, a NULL string HMAC is allowed
898
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
1,028✔
899
        {
900
            hmac->t.size = 0;
129✔
901
            return hmac;
129✔
902
        }
903
    // Start HMAC
904
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
899✔
905

906
    //  Add cpHash
907
    CryptDigestUpdate2B(&hmacState.hashState,
1,798✔
908
                        &ComputeCpHash(command, session->authHashAlg)->b);
899✔
909
    //  Add nonces as required
910
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
899✔
911
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
899✔
912
    if(nonceDecrypt != NULL)
899✔
913
        CryptDigestUpdate2B(&hmacState.hashState, &nonceDecrypt->b);
84✔
914
    if(nonceEncrypt != NULL)
899✔
915
        CryptDigestUpdate2B(&hmacState.hashState, &nonceEncrypt->b);
64✔
916
    //  Add sessionAttributes
917
    buffer      = marshalBuffer;
899✔
918
    marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), &buffer, NULL);
899✔
919
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
899✔
920
    // Complete the HMAC computation
921
    CryptHmacEnd2B(&hmacState, &hmac->b);
899✔
922

923
    return hmac;
899✔
924
}
925

926
//*** CheckSessionHMAC()
927
// This function checks the HMAC of in a session. It uses ComputeCommandHMAC()
928
// to compute the expected HMAC value and then compares the result with the
929
// HMAC in the authorization session. The authorization is successful if they
930
// are the same.
931
//
932
// If the authorizations are not the same, IncrementLockout() is called. It will
933
// return TPM_RC_AUTH_FAIL if the failure caused the failureCount to increment.
934
// Otherwise, it will return TPM_RC_BAD_AUTH.
935
//
936
//  Return Type: TPM_RC
937
//      TPM_RC_AUTH_FAIL        authorization failure caused failureCount increment
938
//      TPM_RC_BAD_AUTH         authorization failure did not cause failureCount
939
//                              increment
940
//
941
static TPM_RC CheckSessionHMAC(
1,028✔
942
                               COMMAND* command,      // IN: primary control structure
943
                               UINT32   sessionIndex  // IN: index of session to be processed
944
                               )
945
{
946
    TPM2B_DIGEST hmac;  // authHMAC for comparing
1,028✔
947
    //
948
    // Compute authHMAC
949
    ComputeCommandHMAC(command, sessionIndex, &hmac);
1,028✔
950

951
    // Compare the input HMAC with the authHMAC computed above.
952
    if(!MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &hmac.b))
1,028✔
953
        {
954
            // If an HMAC session has a failure, invoke the anti-hammering
955
            // if it applies to the authorized entity or the session.
956
            // Otherwise, just indicate that the authorization is bad.
957
            return IncrementLockout(sessionIndex);
10✔
958
        }
959
    return TPM_RC_SUCCESS;
960
}
961

962
//*** CheckPolicyAuthSession()
963
//  This function is used to validate the authorization in a policy session.
964
//  This function performs the following comparisons to see if a policy
965
//  authorization is properly provided. The check are:
966
//  a) compare policyDigest in session with authPolicy associated with
967
//     the entity to be authorized;
968
//  b) compare timeout if applicable;
969
//  c) compare commandCode if applicable;
970
//  d) compare cpHash if applicable; and
971
//  e) see if PCR values have changed since computed.
972
//
973
// If all the above checks succeed, the handle is authorized.
974
// The order of these comparisons is not important because any failure will
975
// result in the same error code.
976
//
977
//  Return Type: TPM_RC
978
//      TPM_RC_PCR_CHANGED          PCR value is not current
979
//      TPM_RC_POLICY_FAIL          policy session fails
980
//      TPM_RC_LOCALITY             command locality is not allowed
981
//      TPM_RC_POLICY_CC            CC doesn't match
982
//      TPM_RC_EXPIRED              policy session has expired
983
//      TPM_RC_PP                   PP is required but not asserted
984
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
985
//      TPM_RC_NV_RATE              NV is rate limiting
986
static TPM_RC CheckPolicyAuthSession(
208✔
987
                                     COMMAND* command,      // IN: primary parsing structure
988
                                     UINT32   sessionIndex  // IN: index of session to be processed
989
                                     )
990
{
991
    SESSION*      session;
208✔
992
    TPM2B_DIGEST  authPolicy;
208✔
993
    TPMI_ALG_HASH policyAlg;
208✔
994
    UINT8         locality;
208✔
995
    //
996
    // Initialize pointer to the authorization session.
997
    session = SessionGet(s_sessionHandles[sessionIndex]);
208✔
998

999
    // If the command is TPM2_PolicySecret(), make sure that
1000
    // either password or authValue is required
1001
    if(command->code == TPM_CC_PolicySecret
208✔
1002
       && session->attributes.isPasswordNeeded == CLEAR
1003
       && session->attributes.isAuthValueNeeded == CLEAR)
×
1004
        return TPM_RC_MODE;
1005
    // See if the PCR counter for the session is still valid.
1006
    if(!SessionPCRValueIsCurrent(session))
208✔
1007
        return TPM_RC_PCR_CHANGED;
1008
    // Get authPolicy.
1009
    policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], &authPolicy);
207✔
1010
    // Compare authPolicy.
1011
    if(!MemoryEqual2B(&session->u2.policyDigest.b, &authPolicy.b))
207✔
1012
        return TPM_RC_POLICY_FAIL;
1013
    // Policy is OK so check if the other factors are correct
1014

1015
    // Compare policy hash algorithm.
1016
    if(policyAlg != session->authHashAlg)
173✔
1017
        return TPM_RC_POLICY_FAIL;
1018

1019
    // Compare timeout.
1020
    if(session->timeout != 0)
173✔
1021
        {
1022
            // Cannot compare time if clock stop advancing.  An TPM_RC_NV_UNAVAILABLE
1023
            // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that
1024
            // a new nonce will be created just that, because TPM time can't advance
1025
            // we can't do time-based operations.
1026
            RETURN_IF_NV_IS_NOT_AVAILABLE;
11✔
1027

1028
            if((session->timeout < g_time) || (session->epoch != g_timeEpoch))
11✔
1029
                return TPM_RC_EXPIRED;
1030
        }
1031
    // If command code is provided it must match
1032
    if(session->commandCode != 0)
173✔
1033
        {
1034
            if(session->commandCode != command->code)
91✔
1035
                return TPM_RC_POLICY_CC;
1036
        }
1037
    else
1038
        {
1039
            // If command requires a DUP or ADMIN authorization, the session must have
1040
            // command code set.
1041
            AUTH_ROLE role = CommandAuthRole(command->index, sessionIndex);
82✔
1042
            if(role == AUTH_ADMIN || role == AUTH_DUP)
82✔
1043
                return TPM_RC_POLICY_FAIL;
1044
        }
1045
    // Check command locality.
1046
    {
1047
        BYTE  sessionLocality[sizeof(TPMA_LOCALITY)];
170✔
1048
        BYTE* buffer = sessionLocality;
170✔
1049

1050
        // Get existing locality setting in canonical form
1051
        sessionLocality[0] = 0;
170✔
1052
        TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
170✔
1053

1054
        // See if the locality has been set
1055
        if(sessionLocality[0] != 0)
170✔
1056
            {
1057
                // If so, get the current locality
1058
                locality = _plat__LocalityGet();
×
1059
                if(locality < 5)
×
1060
                    {
1061
                        if(((sessionLocality[0] & (1 << locality)) == 0)
×
1062
                           || sessionLocality[0] > 31)
×
1063
                            return TPM_RC_LOCALITY;
×
1064
                    }
1065
                else if(locality > 31)
×
1066
                    {
1067
                        if(sessionLocality[0] != locality)
×
1068
                            return TPM_RC_LOCALITY;
1069
                    }
1070
                else
1071
                    {
1072
                        // Could throw an assert here but a locality error is just
1073
                        // as good. It just means that, whatever the locality is, it isn't
1074
                        // the locality requested so...
1075
                        return TPM_RC_LOCALITY;
1076
                    }
1077
            }
1078
    }  // end of locality check
1079
    // Check physical presence.
1080
    if(session->attributes.isPPRequired == SET && !_plat__PhysicalPresenceAsserted())
170✔
1081
        return TPM_RC_PP;
1082
    // Compare cpHash/nameHash/pHash/templateHash if defined.
1083
    if(session->u1.cpHash.b.size != 0)
170✔
1084
        {
1085
            BOOL OK = FALSE;
13✔
1086
            if(session->attributes.isCpHashDefined)
13✔
1087
                // Compare cpHash.
1088
                OK = MemoryEqual2B(&session->u1.cpHash.b,
8✔
1089
                                   &ComputeCpHash(command, session->authHashAlg)->b);
4✔
1090
            else if(g_RuntimeProfile.stateFormatLevel >= 4                // libtpms added
9✔
1091
                    && session->attributes.isNameHashDefined)
9✔
1092
                OK = CompareNameHash(command, session);
3✔
1093
            else if(session->attributes.isParametersHashDefined)
6✔
1094
                OK = CompareParametersHash(command, session);
3✔
1095
            else if(session->attributes.isTemplateHashDefined)
3✔
1096
                OK = CompareTemplateHash(command, session);
3✔
1097
            else if (g_RuntimeProfile.stateFormatLevel < 4)                // libtpms added: backwards compatibility
×
1098
                OK = CompareNameHash(command, session);                        // libtpms added: backwards compatibility
×
1099
            if(!OK)
13✔
1100
                return TPM_RCS_POLICY_FAIL;
2✔
1101
        }
1102
    if(session->attributes.checkNvWritten)
168✔
1103
        {
1104
            NV_REF    locator;
4✔
1105
            NV_INDEX* nvIndex;
4✔
1106
            //
1107
            // If this is not an NV index, the policy makes no sense so fail it.
1108
            if(HandleGetType(s_associatedHandles[sessionIndex]) != TPM_HT_NV_INDEX)
4✔
1109
                return TPM_RC_POLICY_FAIL;
1✔
1110
            // Get the index data
1111
            nvIndex = NvGetIndexInfo(s_associatedHandles[sessionIndex], &locator);
4✔
1112

1113
            // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
1114
            if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
4✔
1115
               != (session->attributes.nvWrittenState == SET))
4✔
1116
                return TPM_RC_POLICY_FAIL;
1117
        }
1118
    return TPM_RC_SUCCESS;
1119
}
1120

1121
//*** RetrieveSessionData()
1122
// This function will unmarshal the sessions in the session area of a command. The
1123
// values are placed in the arrays that are defined at the beginning of this file.
1124
// The normal unmarshaling errors are possible.
1125
//
1126
//  Return Type: TPM_RC
1127
//      TPM_RC_SUCCSS       unmarshaled without error
1128
//      TPM_RC_SIZE         the number of bytes unmarshaled is not the same
1129
//                          as the value for authorizationSize in the command
1130
//
1131
static TPM_RC RetrieveSessionData(
6,220✔
1132
                                  COMMAND* command  // IN: main parsing structure for command
1133
                                  )
1134
{
1135
    int          i;
6,220✔
1136
    TPM_RC       result;
6,220✔
1137
    SESSION*     session;
6,220✔
1138
    TPMA_SESSION sessionAttributes;
6,220✔
1139
    TPM_HT       sessionType;
6,220✔
1140
    INT32        sessionIndex;
6,220✔
1141
    TPM_RC       errorIndex;
6,220✔
1142
    //
1143
    s_decryptSessionIndex = UNDEFINED_INDEX;
6,220✔
1144
    s_encryptSessionIndex = UNDEFINED_INDEX;
6,220✔
1145
    s_auditSessionIndex   = UNDEFINED_INDEX;
6,220✔
1146

1147
    for(sessionIndex = 0; command->authSize > 0; sessionIndex++)
12,929✔
1148
        {
1149
            errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,759✔
1150

1151
            // If maximum allowed number of sessions has been parsed, return a size
1152
            // error with a session number that is larger than the number of allowed
1153
            // sessions
1154
            if(sessionIndex == MAX_SESSION_NUM)
6,759✔
1155
                return TPM_RCS_SIZE + errorIndex;
4✔
1156
            // make sure that the associated handle for each session starts out
1157
            // unassigned
1158
            s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
6,755✔
1159

1160
            // First parameter: Session handle.
1161
            result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
6,755✔
1162
                                                    &command->parameterBuffer,
1163
                                                    &command->authSize,
1164
                                                    TRUE);
1165
            if(result != TPM_RC_SUCCESS)
6,755✔
1166
                return result + TPM_RC_S + g_rcIndex[sessionIndex];
16✔
1167
            // Second parameter: Nonce.
1168
            result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
6,739✔
1169
                                           &command->parameterBuffer,
1170
                                           &command->authSize);
1171
            if(result != TPM_RC_SUCCESS)
6,739✔
1172
                return result + TPM_RC_S + g_rcIndex[sessionIndex];
8✔
1173
            // Third parameter: sessionAttributes.
1174
            result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
6,731✔
1175
                                            &command->parameterBuffer,
1176
                                            &command->authSize);
1177
            if(result != TPM_RC_SUCCESS)
6,731✔
1178
                return result + TPM_RC_S + g_rcIndex[sessionIndex];
4✔
1179
            // Fourth parameter: authValue (PW or HMAC).
1180
            result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
6,727✔
1181
                                          &command->parameterBuffer,
1182
                                          &command->authSize);
1183
            if(result != TPM_RC_SUCCESS)
6,727✔
1184
                return result + errorIndex;
4✔
1185

1186
            sessionAttributes = s_attributes[sessionIndex];
6,723✔
1187
            if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,723✔
1188
                {
1189
                    // A PWAP session needs additional processing.
1190
                    //     Can't have any attributes set other than continueSession bit
1191
                    if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)
5,638✔
1192
                       || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)
1193
                       || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)
5,638✔
1194
                       || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
1195
                       || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset))
5,634✔
1196
                        return TPM_RCS_ATTRIBUTES + errorIndex;
4✔
1197
                    //     The nonce size must be zero.
1198
                    if(s_nonceCaller[sessionIndex].t.size != 0)
5,634✔
1199
                        return TPM_RCS_NONCE + errorIndex;
4✔
1200
                    continue;
5,630✔
1201
                }
1202
            // For not password sessions...
1203
            // Find out if the session is loaded.
1204
            if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
1,085✔
1205
                return TPM_RC_REFERENCE_S0 + sessionIndex;
6✔
1206
            sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
1,079✔
1207
            session     = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1208

1209
            // Check if the session is an HMAC/policy session.
1210
            if((session->attributes.isPolicy == SET && sessionType == TPM_HT_HMAC_SESSION)
1,079✔
1211
               || (session->attributes.isPolicy == CLEAR
1,079✔
1212
                   && sessionType == TPM_HT_POLICY_SESSION))
871✔
1213
                return TPM_RCS_HANDLE + errorIndex;
×
1214
            // Check that this handle has not previously been used.
1215
            for(i = 0; i < sessionIndex; i++)
1,410✔
1216
                {
1217
                    if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
331✔
1218
                        return TPM_RCS_HANDLE + errorIndex;
×
1219
                }
1220
            // If the session is used for parameter encryption or audit as well, set
1221
            // the corresponding Indexes.
1222

1223
            // First process decrypt.
1224
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt))
1,079✔
1225
                {
1226
                    // Check if the commandCode allows command parameter encryption.
1227
                    if(DecryptSize(command->index) == 0)
162✔
1228
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1229
                    // Encrypt attribute can only appear in one session
1230
                    if(s_decryptSessionIndex != UNDEFINED_INDEX)
162✔
1231
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1232
                    // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
1233
                    if(session->symmetric.algorithm == TPM_ALG_NULL)
162✔
1234
                        return TPM_RCS_SYMMETRIC + errorIndex;
×
1235
                    // All checks passed, so set the index for the session used to decrypt
1236
                    // a command parameter.
1237
                    s_decryptSessionIndex = sessionIndex;
162✔
1238
                }
1239
            // Now process encrypt.
1240
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt))
1,079✔
1241
                {
1242
                    // Check if the commandCode allows response parameter encryption.
1243
                    if(EncryptSize(command->index) == 0)
154✔
1244
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1245
                    // Encrypt attribute can only appear in one session.
1246
                    if(s_encryptSessionIndex != UNDEFINED_INDEX)
154✔
1247
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1248
                    // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
1249
                    if(session->symmetric.algorithm == TPM_ALG_NULL)
154✔
1250
                        return TPM_RCS_SYMMETRIC + errorIndex;
×
1251
                    // All checks passed, so set the index for the session used to encrypt
1252
                    // a response parameter.
1253
                    s_encryptSessionIndex = sessionIndex;
154✔
1254
                }
1255
            // At last process audit.
1256
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit))
1,079✔
1257
                {
1258
                    // Audit attribute can only appear in one session.
1259
                    if(s_auditSessionIndex != UNDEFINED_INDEX)
35✔
1260
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1261
                    // An audit session can not be policy session.
1262
                    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION)
35✔
1263
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1264
                    // If this is a reset of the audit session, or the first use
1265
                    // of the session as an audit session, it doesn't matter what
1266
                    // the exclusive state is. The session will become exclusive.
1267
                    if(!IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset)
35✔
1268
                       && session->attributes.isAudit == SET)
35✔
1269
                        {
1270
                            // Not first use or reset. If auditExlusive is SET, then this
1271
                            // session must be the current exclusive session.
1272
                            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
14✔
1273
                               && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
×
1274
                                return TPM_RC_EXCLUSIVE;
1275
                        }
1276
                    s_auditSessionIndex = sessionIndex;
35✔
1277
                }
1278
            // Initialize associated handle as undefined. This will be changed when
1279
            // the handles are processed.
1280
            s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1,079✔
1281
        }
1282
    command->sessionNum = sessionIndex;
6,170✔
1283
    return TPM_RC_SUCCESS;
6,170✔
1284
}
1285

1286
//*** CheckLockedOut()
1287
// This function checks to see if the TPM is in lockout. This function should only
1288
// be called if the entity being checked is subject to DA protection. The TPM
1289
// is in lockout if the NV is not available and a DA write is pending. Otherwise
1290
// the TPM is locked out if checking for lockoutAuth ('lockoutAuthCheck' == TRUE)
1291
// and use of lockoutAuth is disabled, or 'failedTries' >= 'maxTries'
1292
//  Return Type: TPM_RC
1293
//      TPM_RC_NV_RATE          NV is rate limiting
1294
//      TPM_RC_NV_UNAVAILABLE   NV is not available at this time
1295
//      TPM_RC_LOCKOUT          TPM is in lockout
1296
static TPM_RC CheckLockedOut(
159✔
1297
                             BOOL lockoutAuthCheck  // IN: TRUE if checking is for lockoutAuth
1298
                             )
1299
{
1300
    // If NV is unavailable, and current cycle state recorded in NV is not
1301
    // SU_NONE_VALUE, refuse to check any authorization because we would
1302
    // not be able to handle a DA failure.
1303
    if(!NV_IS_AVAILABLE && NV_IS_ORDERLY)
159✔
1304
        return g_NvStatus;
1305
    // Check if DA info needs to be updated in NV.
1306
    if(s_DAPendingOnNV)
159✔
1307
        {
1308
            // If NV is accessible,
1309
            RETURN_IF_NV_IS_NOT_AVAILABLE;
×
1310

1311
            // ... write the pending DA data and proceed.
1312
            NV_SYNC_PERSISTENT(lockOutAuthEnabled);
×
1313
            NV_SYNC_PERSISTENT(failedTries);
×
1314
            s_DAPendingOnNV = FALSE;
×
1315
        }
1316
    // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1317
    // is disabled...
1318
    if(lockoutAuthCheck)
159✔
1319
        {
1320
            if(gp.lockOutAuthEnabled == FALSE)
80✔
1321
                return TPM_RC_LOCKOUT;
×
1322
        }
1323
    else
1324
        {
1325
            // ... or if the number of failed tries has been maxed out.
1326
            if(gp.failedTries >= gp.maxTries)
79✔
1327
                return TPM_RC_LOCKOUT;
1328
#if USE_DA_USED
1329
            // If the daUsed flag is not SET, then no DA validation until the
1330
            // daUsed state is written to NV
1331
            if(!g_daUsed)
41✔
1332
                {
1333
                    RETURN_IF_NV_IS_NOT_AVAILABLE;
10✔
1334
                    g_daUsed        = TRUE;
10✔
1335
                    gp.orderlyState = SU_DA_USED_VALUE;
10✔
1336
                    NV_SYNC_PERSISTENT(orderlyState);
10✔
1337
                    return TPM_RC_SUCCESS; // libtpms changed: was TPM_RC_RETRY;
10✔
1338
                }
1339
#endif
1340
        }
1341
    return TPM_RC_SUCCESS;
1342
}
1343

1344
//*** CheckAuthSession()
1345
// This function checks that the authorization session properly authorizes the
1346
// use of the associated handle.
1347
//
1348
//  Return Type: TPM_RC
1349
//      TPM_RC_LOCKOUT              entity is protected by DA and TPM is in
1350
//                                  lockout, or TPM is locked out on NV update
1351
//                                  pending on DA parameters
1352
//
1353
//      TPM_RC_PP                   Physical Presence is required but not provided
1354
//      TPM_RC_AUTH_FAIL            HMAC or PW authorization failed
1355
//                                  with DA side-effects (can be a policy session)
1356
//
1357
//      TPM_RC_BAD_AUTH             HMAC or PW authorization failed without DA
1358
//                                  side-effects (can be a policy session)
1359
//
1360
//      TPM_RC_POLICY_FAIL          if policy session fails
1361
//      TPM_RC_POLICY_CC            command code of policy was wrong
1362
//      TPM_RC_EXPIRED              the policy session has expired
1363
//      TPM_RC_PCR
1364
//      TPM_RC_AUTH_UNAVAILABLE     authValue or authPolicy unavailable
1365
static TPM_RC CheckAuthSession(
6,568✔
1366
                               COMMAND* command,      // IN: primary parsing structure
1367
                               UINT32   sessionIndex  // IN: index of session to be processed
1368
                               )
1369
{
1370
    TPM_RC     result            = TPM_RC_SUCCESS;
6,568✔
1371
    SESSION*   session           = NULL;
6,568✔
1372
    TPM_HANDLE sessionHandle     = s_sessionHandles[sessionIndex];
6,568✔
1373
    TPM_HANDLE associatedHandle  = s_associatedHandles[sessionIndex];
6,568✔
1374
    TPM_HT     sessionHandleType = HandleGetType(sessionHandle);
6,568✔
1375
    BOOL       authUsed;
6,568✔
1376
    //
1377
    pAssert(sessionHandle != TPM_RH_UNASSIGNED);
6,568✔
1378

1379
    // Take care of physical presence
1380
    if(associatedHandle == TPM_RH_PLATFORM)
6,568✔
1381
        {
1382
            // If the physical presence is required for this command, check for PP
1383
            // assertion. If it isn't asserted, no point going any further.
1384
            if(PhysicalPresenceIsRequired(command->index)
964✔
1385
               && !_plat__PhysicalPresenceAsserted())
12✔
1386
                return TPM_RC_PP;
1387
        }
1388
    if(sessionHandle != TPM_RS_PW)
6,556✔
1389
        {
1390
            session = SessionGet(sessionHandle);
980✔
1391

1392
            // Set includeAuth to indicate if DA checking will be required and if the
1393
            // authValue will be included in any HMAC.
1394
            if(sessionHandleType == TPM_HT_POLICY_SESSION)
980✔
1395
                {
1396
                    // For a policy session, will check the DA status of the entity if either
1397
                    // isAuthValueNeeded or isPasswordNeeded is SET.
1398
                    session->attributes.includeAuth = session->attributes.isAuthValueNeeded
208✔
1399
                                                      || session->attributes.isPasswordNeeded;
208✔
1400
                }
1401
            else
1402
                {
1403
                    // For an HMAC session, need to check unless the session
1404
                    // is bound.
1405
                    session->attributes.includeAuth =
1,544✔
1406
                        !IsSessionBindEntity(s_associatedHandles[sessionIndex], session);
772✔
1407
                }
1408
            authUsed = session->attributes.includeAuth;
980✔
1409
        }
1410
    else
1411
        // Password session
1412
        authUsed = TRUE;
1413
    // If the authorization session is going to use an authValue, then make sure
1414
    // that access to that authValue isn't locked out.
1415
    if(authUsed)
980✔
1416
        {
1417
            // See if entity is subject to lockout.
1418
            if(!IsDAExempted(associatedHandle))
6,321✔
1419
                {
1420
                    // See if in lockout
1421
                    result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
159✔
1422
                    if(result != TPM_RC_SUCCESS)
159✔
1423
                        return result;
1424
                }
1425
        }
1426
    // Policy or HMAC+PW?
1427
    if(sessionHandleType != TPM_HT_POLICY_SESSION)
6,518✔
1428
        {
1429
            // for non-policy session make sure that a policy session is not required
1430
            if(IsPolicySessionRequired(command->index, sessionIndex))
6,310✔
1431
                return TPM_RC_AUTH_TYPE;
1432
            // The authValue must be available.
1433
            // Note: The authValue is going to be "used" even if it is an EmptyAuth.
1434
            // and the session is bound.
1435
            if(!IsAuthValueAvailable(associatedHandle, command->index, sessionIndex))
6,308✔
1436
                return TPM_RC_AUTH_UNAVAILABLE;
1437
        }
1438
    else
1439
        {
1440
            // ... see if the entity has a policy, ...
1441
            // Note: IsAuthPolicyAvalable will return FALSE if the sensitive area of the
1442
            // object is not loaded
1443
            if(!IsAuthPolicyAvailable(associatedHandle, command->index, sessionIndex))
208✔
1444
                return TPM_RC_AUTH_UNAVAILABLE;
1445
            // ... and check the policy session.
1446
            result = CheckPolicyAuthSession(command, sessionIndex);
208✔
1447
            if(result != TPM_RC_SUCCESS)
208✔
1448
                return result;
1449
        }
1450
    // Check authorization according to the type
1451
    if((TPM_RS_PW == sessionHandle) || (session->attributes.isPasswordNeeded == SET))
6,448✔
1452
        result = CheckPWAuthSession(sessionIndex);
5,519✔
1453
    else
1454
        result = CheckSessionHMAC(command, sessionIndex);
929✔
1455
    // Do processing for PIN Indexes are only three possibilities for 'result' at
1456
    // this point: TPM_RC_SUCCESS, TPM_RC_AUTH_FAIL, and TPM_RC_BAD_AUTH.
1457
    // For all these cases, we would have to process a PIN index if the
1458
    // authValue of the index was used for authorization.
1459
    if((TPM_HT_NV_INDEX == HandleGetType(associatedHandle)) && authUsed)
6,448✔
1460
        {
1461
            NV_REF    locator;
489✔
1462
            NV_INDEX* nvIndex = NvGetIndexInfo(associatedHandle, &locator);
489✔
1463
            NV_PIN    pinData;
489✔
1464
            TPMA_NV   nvAttributes;
489✔
1465
            //
1466
            pAssert(nvIndex != NULL);
489✔
1467
            nvAttributes = nvIndex->publicArea.attributes;
489✔
1468
            // If this is a PIN FAIL index and the value has been written
1469
            // then we can update the counter (increment or clear)
1470
            if(IsNvPinFailIndex(nvAttributes)
489✔
1471
               && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
13✔
1472
                {
1473
                    pinData.intVal = NvGetUINT64Data(nvIndex, locator);
13✔
1474
                    if(result != TPM_RC_SUCCESS)
13✔
1475
                        pinData.pin.pinCount++;
6✔
1476
                    else
1477
                        pinData.pin.pinCount = 0;
7✔
1478
                    NvWriteUINT64Data(nvIndex, pinData.intVal);
13✔
1479
                }
1480
            // If this is a PIN PASS Index, increment if we have used the
1481
            // authorization value.
1482
            // NOTE: If the counter has already hit the limit, then we
1483
            // would not get here because the authorization value would not
1484
            // be available and the TPM would have returned before it gets here
1485
            else if(IsNvPinPassIndex(nvAttributes)
476✔
1486
                    && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN)
8✔
1487
                    && result == TPM_RC_SUCCESS)
8✔
1488
                {
1489
                    // If the access is valid, then increment the use counter
1490
                    pinData.intVal = NvGetUINT64Data(nvIndex, locator);
7✔
1491
                    pinData.pin.pinCount++;
7✔
1492
                    NvWriteUINT64Data(nvIndex, pinData.intVal);
7✔
1493
                }
1494
        }
1495
    return result;
1496
}
1497

1498
#if CC_GetCommandAuditDigest
1499
//*** CheckCommandAudit()
1500
// This function is called before the command is processed if audit is enabled
1501
// for the command. It will check to see if the audit can be performed and
1502
// will ensure that the cpHash is available for the audit.
1503
//  Return Type: TPM_RC
1504
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
1505
//      TPM_RC_NV_RATE              NV is rate limiting
1506
static TPM_RC CheckCommandAudit(COMMAND* command)
65✔
1507
{
1508
    // If the audit digest is clear and command audit is required, NV must be
1509
    // available so that TPM2_GetCommandAuditDigest() is able to increment
1510
    // audit counter. If NV is not available, the function bails out to prevent
1511
    // the TPM from attempting an operation that would fail anyway.
1512
    if(gr.commandAuditDigest.t.size == 0
65✔
1513
       || GetCommandCode(command->index) == TPM_CC_GetCommandAuditDigest)
×
1514
        {
1515
            RETURN_IF_NV_IS_NOT_AVAILABLE;
65✔
1516
        }
1517
    // Make sure that the cpHash is computed for the algorithm
1518
    ComputeCpHash(command, gp.auditHashAlg);
65✔
1519
    return TPM_RC_SUCCESS;
65✔
1520
}
1521
#endif
1522

1523
//*** ParseSessionBuffer()
1524
// This function is the entry function for command session processing.
1525
// It iterates sessions in session area and reports if the required authorization
1526
// has been properly provided. It also processes audit session and passes the
1527
// information of encryption sessions to parameter encryption module.
1528
//
1529
//  Return Type: TPM_RC
1530
//        various           parsing failure or authorization failure
1531
//
1532
TPM_RC
1533
ParseSessionBuffer(COMMAND* command  // IN: the structure that contains
6,220✔
1534
                   )
1535
{
1536
    TPM_RC     result;
6,220✔
1537
    UINT32     i;
6,220✔
1538
    INT32      size = 0;
6,220✔
1539
    TPM2B_AUTH extraKey;
6,220✔
1540
    UINT32     sessionIndex;
6,220✔
1541
    TPM_RC     errorIndex;
6,220✔
1542
    SESSION*   session = NULL;
6,220✔
1543
    //
1544
    // Check if a command allows any session in its session area.
1545
    if(!IsSessionAllowed(command->index))
6,220✔
1546
        return TPM_RC_AUTH_CONTEXT;
1547
    // Default-initialization.
1548
    command->sessionNum = 0;
6,220✔
1549

1550
    result              = RetrieveSessionData(command);
6,220✔
1551
    if(result != TPM_RC_SUCCESS)
6,220✔
1552
        return result;
1553
    // There is no command in the TPM spec that has more handles than
1554
    // MAX_SESSION_NUM.
1555
    pAssert(command->handleNum <= MAX_SESSION_NUM);
6,170✔
1556

1557
    // Associate the session with an authorization handle.
1558
    for(i = 0; i < command->handleNum; i++)
14,556✔
1559
        {
1560
            if(CommandAuthRole(command->index, i) != AUTH_NONE)
8,386✔
1561
                {
1562
                    // If the received session number is less than the number of handles
1563
                    // that requires authorization, an error should be returned.
1564
                    // Note: for all the TPM 2.0 commands, handles requiring
1565
                    // authorization come first in a command input and there are only ever
1566
                    // two values requiring authorization
1567
                    if(command->sessionNum == 0)                // libtpms added begin (Coverity 1550499)
6,574✔
1568
                        return TPM_RC_AUTH_MISSING;                // libtpms added end
1569
                    if(i > (command->sessionNum - 1))
6,574✔
1570
                        return TPM_RC_AUTH_MISSING;
1571
                    // Record the handle associated with the authorization session
1572
                    s_associatedHandles[i] = HierarchyNormalizeHandle(command->handles[i]);
6,574✔
1573
                }
1574
        }
1575
    // Consistency checks are done first to avoid authorization failure when the
1576
    // command will not be executed anyway.
1577
    for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++)
12,628✔
1578
        {
1579
            errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,679✔
1580
            // PW session must be an authorization session
1581
            if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,679✔
1582
                {
1583
                    if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
5,600✔
1584
                        return TPM_RCS_HANDLE + errorIndex;
12✔
1585
                    // a password session can't be audit, encrypt or decrypt
1586
                    if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
5,588✔
1587
                       || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1588
                       || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
5,588✔
1589
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1590
                    session = NULL;
1591
                }
1592
            else
1593
                {
1594
                    session = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1595

1596
                    // A trial session can not appear in session area, because it cannot
1597
                    // be used for authorization, audit or encrypt/decrypt.
1598
                    if(session->attributes.isTrialPolicy == SET)
1,079✔
1599
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1600

1601
                    // See if the session is bound to a DA protected entity
1602
                    // NOTE: Since a policy session is never bound, a policy is still
1603
                    // usable even if the object is DA protected and the TPM is in
1604
                    // lockout.
1605
                    if(session->attributes.isDaBound == SET)
1,079✔
1606
                        {
1607
                            result = CheckLockedOut(session->attributes.isLockoutBound == SET);
×
1608
                            if(result != TPM_RC_SUCCESS)
×
1609
                                return result;
×
1610
                        }
1611
                    // If this session is for auditing, make sure the cpHash is computed.
1612
                    if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit))
1,079✔
1613
                        ComputeCpHash(command, session->authHashAlg);
35✔
1614
                }
1615

1616
            // if the session has an associated handle, check the authorization
1617
            if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
6,667✔
1618
                {
1619
                    result = CheckAuthSession(command, sessionIndex);
6,568✔
1620
                    if(result != TPM_RC_SUCCESS)
6,568✔
1621
                        return RcSafeAddToResult(result, errorIndex);
209✔
1622
                }
1623
            else
1624
                {
1625
                    // a session that is not for authorization must either be encrypt,
1626
                    // decrypt, or audit
1627
                    if(!IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
99✔
1628
                       && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1629
                       && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
88✔
1630
                        return TPM_RCS_ATTRIBUTES + errorIndex;
×
1631

1632
                    // no authValue included in any of the HMAC computations
1633
                    pAssert(session != NULL);
99✔
1634
                    session->attributes.includeAuth = CLEAR;
99✔
1635

1636
                    // check HMAC for encrypt/decrypt/audit only sessions
1637
                    result = CheckSessionHMAC(command, sessionIndex);
99✔
1638
                    if(result != TPM_RC_SUCCESS)
99✔
1639
                        return RcSafeAddToResult(result, errorIndex);
×
1640
                }
1641
        }
1642
#if CC_GetCommandAuditDigest
1643
    // Check if the command should be audited. Need to do this before any parameter
1644
    // encryption so that the cpHash for the audit is correct
1645
    if(CommandAuditIsRequired(command->index))
5,949✔
1646
        {
1647
            result = CheckCommandAudit(command);
65✔
1648
            if(result != TPM_RC_SUCCESS)
65✔
1649
                return result;  // No session number to reference
1650
        }
1651
#endif
1652
    // Decrypt the first parameter if applicable. This should be the last operation
1653
    // in session processing.
1654
    // If the encrypt session is associated with a handle and the handle's
1655
    // authValue is available, then authValue is concatenated with sessionKey to
1656
    // generate encryption key, no matter if the handle is the session bound entity
1657
    // or not.
1658
    if(s_decryptSessionIndex != UNDEFINED_INDEX)
5,949✔
1659
        {
1660
            // If this is an authorization session, include the authValue in the
1661
            // generation of the decryption key
1662
            if(s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED)
160✔
1663
                {
1664
                    EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], &extraKey);
110✔
1665
                }
1666
            else
1667
                {
1668
                    extraKey.b.size = 0;
50✔
1669
                }
1670
            size   = DecryptSize(command->index);
160✔
1671
            result = CryptParameterDecryption(s_sessionHandles[s_decryptSessionIndex],
320✔
1672
                                              &s_nonceCaller[s_decryptSessionIndex].b,
160✔
1673
                                              command->parameterSize,
1674
                                              (UINT16)size,
1675
                                              &extraKey,
1676
                                              command->parameterBuffer);
1677
            if(result != TPM_RC_SUCCESS)
160✔
1678
                return RcSafeAddToResult(result,
2✔
1679
                                         TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
2✔
1680
        }
1681

1682
    return TPM_RC_SUCCESS;
1683
}
1684

1685
//*** CheckAuthNoSession()
1686
// Function to process a command with no session associated.
1687
// The function makes sure all the handles in the command require no authorization.
1688
//
1689
//  Return Type: TPM_RC
1690
//      TPM_RC_AUTH_MISSING         failure - one or more handles require
1691
//                                  authorization
1692
TPM_RC
1693
CheckAuthNoSession(COMMAND* command  // IN: command parsing structure
10,476✔
1694
                   )
1695
{
1696
    UINT32 i;
10,476✔
1697
#if CC_GetCommandAuditDigest
1698
    TPM_RC result = TPM_RC_SUCCESS;
10,476✔
1699
#endif
1700
    //
1701
    // Check if the command requires authorization
1702
    for(i = 0; i < command->handleNum; i++)
13,019✔
1703
        {
1704
            if(CommandAuthRole(command->index, i) != AUTH_NONE)
2,567✔
1705
                return TPM_RC_AUTH_MISSING;
1706
        }
1707
#if CC_GetCommandAuditDigest
1708
    // Check if the command should be audited.
1709
    if(CommandAuditIsRequired(command->index))
10,452✔
1710
        {
1711
            result = CheckCommandAudit(command);
×
1712
            if(result != TPM_RC_SUCCESS)
×
1713
                return result;
1714
        }
1715
#endif
1716
    // Initialize number of sessions to be 0
1717
    command->sessionNum = 0;
10,452✔
1718

1719
    return TPM_RC_SUCCESS;
10,452✔
1720
}
1721

1722
//** Response Session Processing
1723
//*** Introduction
1724
//
1725
//  The following functions build the session area in a response and handle
1726
//  the audit sessions (if present).
1727
//
1728

1729
//*** ComputeRpHash()
1730
// Function to compute rpHash (Response Parameter Hash). The rpHash is only
1731
// computed if there is an HMAC authorization session and the return code is
1732
// TPM_RC_SUCCESS.
1733
static TPM2B_DIGEST* ComputeRpHash(
1,026✔
1734
                                   COMMAND*   command,  // IN: command structure
1735
                                   TPM_ALG_ID hashAlg   // IN: hash algorithm to compute rpHash
1736
                                   )
1737
{
1738
    TPM2B_DIGEST* rpHash = GetRpHashPointer(command, hashAlg);
1,026✔
1739
    HASH_STATE    hashState;
1,026✔
1740
    //
1741
    if(rpHash->t.size == 0)
1,026✔
1742
        {
1743
            //   rpHash := hash(responseCode || commandCode || parameters)
1744

1745
            // Initiate hash creation.
1746
            rpHash->t.size = CryptHashStart(&hashState, hashAlg);
749✔
1747

1748
            // Add hash constituents.
1749
            CryptDigestUpdateInt(&hashState, sizeof(TPM_RC), TPM_RC_SUCCESS);
749✔
1750
            CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
749✔
1751
            CryptDigestUpdate(
749✔
1752
                              &hashState, command->parameterSize, command->parameterBuffer);
749✔
1753
            // Complete hash computation.
1754
            CryptHashEnd2B(&hashState, &rpHash->b);
749✔
1755
        }
1756
    return rpHash;
1,026✔
1757
}
1758

1759
//*** InitAuditSession()
1760
// This function initializes the audit data in an audit session.
1761
static void InitAuditSession(SESSION* session  // session to be initialized
21✔
1762
                             )
1763
{
1764
    // Mark session as an audit session.
1765
    session->attributes.isAudit = SET;
21✔
1766

1767
    // Audit session can not be bound.
1768
    session->attributes.isBound = CLEAR;
21✔
1769

1770
    // Size of the audit log is the size of session hash algorithm digest.
1771
    session->u2.auditDigest.t.size = CryptHashGetDigestSize(session->authHashAlg);
21✔
1772

1773
    // Set the original digest value to be 0.
1774
    MemorySet(&session->u2.auditDigest.t.buffer, 0, session->u2.auditDigest.t.size);
21✔
1775
    return;
21✔
1776
}
1777

1778
//*** UpdateAuditDigest
1779
// Function to update an audit digest
1780
static void UpdateAuditDigest(
52✔
1781
                              COMMAND* command, TPMI_ALG_HASH hashAlg, TPM2B_DIGEST* digest)
1782
{
1783
    HASH_STATE    hashState;
52✔
1784
    TPM2B_DIGEST* cpHash = GetCpHash(command, hashAlg);
52✔
1785
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, hashAlg);
52✔
1786
    //
1787
    pAssert(cpHash != NULL);
52✔
1788

1789
    // digestNew :=  hash (digestOld || cpHash || rpHash)
1790
    // Start hash computation.
1791
    digest->t.size = CryptHashStart(&hashState, hashAlg);
52✔
1792
    // Add old digest.
1793
    CryptDigestUpdate2B(&hashState, &digest->b);
52✔
1794
    // Add cpHash
1795
    CryptDigestUpdate2B(&hashState, &cpHash->b);
52✔
1796
    // Add rpHash
1797
    CryptDigestUpdate2B(&hashState, &rpHash->b);
52✔
1798
    // Finalize the hash.
1799
    CryptHashEnd2B(&hashState, &digest->b);
52✔
1800
}
52✔
1801

1802
//*** Audit()
1803
//This function updates the audit digest in an audit session.
1804
static void Audit(COMMAND* command,      // IN: primary control structure
35✔
1805
                  SESSION* auditSession  // IN: loaded audit session
1806
                  )
1807
{
1808
    UpdateAuditDigest(
35✔
1809
                      command, auditSession->authHashAlg, &auditSession->u2.auditDigest);
35✔
1810
    return;
35✔
1811
}
1812

1813
#if CC_GetCommandAuditDigest
1814
//*** CommandAudit()
1815
// This function updates the command audit digest.
1816
static void CommandAudit(COMMAND* command  // IN:
17✔
1817
                         )
1818
{
1819
    // If the digest.size is one, it indicates the special case of changing
1820
    // the audit hash algorithm. For this case, no audit is done on exit.
1821
    // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1822
    // force an update to the NV on exit so that the change in digest will
1823
    // be recorded. So, it is safe to exit here without setting any flags
1824
    // because the digest change will be written to NV when this code exits.
1825
    if(gr.commandAuditDigest.t.size == 1)
17✔
1826
        {
1827
            gr.commandAuditDigest.t.size = 0;
×
1828
            return;
×
1829
        }
1830
    // If the digest size is zero, need to start a new digest and increment
1831
    // the audit counter.
1832
    if(gr.commandAuditDigest.t.size == 0)
17✔
1833
        {
1834
            gr.commandAuditDigest.t.size = CryptHashGetDigestSize(gp.auditHashAlg);
17✔
1835
            MemorySet(gr.commandAuditDigest.t.buffer, 0, gr.commandAuditDigest.t.size);
17✔
1836

1837
            // Bump the counter and save its value to NV.
1838
            gp.auditCounter++;
17✔
1839
            NV_SYNC_PERSISTENT(auditCounter);
17✔
1840
        }
1841
    UpdateAuditDigest(command, gp.auditHashAlg, &gr.commandAuditDigest);
17✔
1842
    return;
17✔
1843
}
1844
#endif
1845

1846
//*** UpdateAuditSessionStatus()
1847
// This function updates the internal audit related states of a session. It will:
1848
//  a) initialize the session as audit session and set it to be exclusive if this
1849
//     is the first time it is used for audit or audit reset was requested;
1850
//  b) report exclusive audit session;
1851
//  c) extend audit log; and
1852
//  d) clear exclusive audit session if no audit session found in the command.
1853
static void UpdateAuditSessionStatus(
14,469✔
1854
                                     COMMAND* command  // IN: primary control structure
1855
                                     )
1856
{
1857
    UINT32     i;
14,469✔
1858
    TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
14,469✔
1859
    //
1860
    // Iterate through sessions
1861
    for(i = 0; i < command->sessionNum; i++)
20,065✔
1862
        {
1863
            SESSION* session;
5,596✔
1864
            //
1865
            // PW session do not have a loaded session and can not be an audit
1866
            // session either.  Skip it.
1867
            if(s_sessionHandles[i] == TPM_RS_PW)
5,596✔
1868
                continue;
4,618✔
1869
            session = SessionGet(s_sessionHandles[i]);
978✔
1870

1871
            // If a session is used for audit
1872
            if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit))
978✔
1873
                {
1874
                    // An audit session has been found
1875
                    auditSession = s_sessionHandles[i];
35✔
1876

1877
                    // If the session has not been an audit session yet, or
1878
                    // the auditSetting bits indicate a reset, initialize it and set
1879
                    // it to be the exclusive session
1880
                    if(session->attributes.isAudit == CLEAR
35✔
1881
                       || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset))
14✔
1882
                        {
1883
                            InitAuditSession(session);
21✔
1884
                            g_exclusiveAuditSession = auditSession;
21✔
1885
                        }
1886
                    else
1887
                        {
1888
                            // Check if the audit session is the current exclusive audit
1889
                            // session and, if not, clear previous exclusive audit session.
1890
                            if(g_exclusiveAuditSession != auditSession)
14✔
1891
                                g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
5✔
1892
                        }
1893
                    // Report audit session exclusivity.
1894
                    if(g_exclusiveAuditSession == auditSession)
35✔
1895
                        {
1896
                            SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
30✔
1897
                        }
1898
                    else
1899
                        {
1900
                            CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
5✔
1901
                        }
1902
                    // Extend audit log.
1903
                    Audit(command, session);
5,631✔
1904
                }
1905
        }
1906
    // If no audit session is found in the command, and the command allows
1907
    // a session then, clear the current exclusive
1908
    // audit session.
1909
    if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index))
14,469✔
1910
        {
1911
            g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
9,170✔
1912
        }
1913
    return;
14,469✔
1914
}
1915

1916
//*** ComputeResponseHMAC()
1917
// Function to compute HMAC for authorization session in a response.
1918
/*(See part 1 specification)
1919
// Function: Compute HMAC for response sessions
1920
//      The sessionAuth value
1921
//          authHMAC := HMACsHASH((sessionAuth | authValue),
1922
//                    (pHash | nonceTPM | nonceCaller | sessionAttributes))
1923
//  Where:
1924
//      HMACsHASH()     The HMAC algorithm using the hash algorithm specified when
1925
//                      the session was started.
1926
//
1927
//      sessionAuth     A TPMB_MEDIUM computed in a protocol-dependent way, using
1928
//                      KDFa. In an HMAC or KDF, only sessionAuth.buffer is used.
1929
//
1930
//      authValue       A TPM2B_AUTH that is found in the sensitive area of an
1931
//                      object. In an HMAC or KDF, only authValue.buffer is used
1932
//                      and all trailing zeros are removed.
1933
//
1934
//      pHash           Response parameters (rpHash) using the session hash. When
1935
//                      using a pHash in an HMAC computation, both the algorithm ID
1936
//                      and the digest are included.
1937
//
1938
//      nonceTPM        A TPM2B_NONCE that is generated by the entity using the
1939
//                      session. In an HMAC or KDF, only nonceTPM.buffer is used.
1940
//
1941
//      nonceCaller     a TPM2B_NONCE that was received the previous time the
1942
//                      session was used. In an HMAC or KDF, only
1943
//                      nonceCaller.buffer is used.
1944
//
1945
//      sessionAttributes   A TPMA_SESSION that indicates the attributes associated
1946
//                          with a particular use of the session.
1947
*/
1948
static void ComputeResponseHMAC(
974✔
1949
                                COMMAND*      command,       // IN: command structure
1950
                                UINT32        sessionIndex,  // IN: session index to be processed
1951
                                SESSION*      session,       // IN: loaded session
1952
                                TPM2B_DIGEST* hmac           // OUT: authHMAC
1953
                                )
1954
{
1955
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
974✔
1956
    TPM2B_KEY     key;  // HMAC key
974✔
1957
    BYTE          marshalBuffer[sizeof(TPMA_SESSION)];
974✔
1958
    BYTE*         buffer;
974✔
1959
    UINT32        marshalSize;
974✔
1960
    HMAC_STATE    hmacState;
974✔
1961
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, session->authHashAlg);
974✔
1962
    //
1963
    // Generate HMAC key
1964
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
974✔
1965

1966
    // Add the object authValue if required
1967
    if(session->attributes.includeAuth == SET)
974✔
1968
        {
1969
            // Note: includeAuth may be SET for a policy that is used in
1970
            // UndefineSpaceSpecial(). At this point, the Index has been deleted
1971
            // so the includeAuth will have no meaning. However, the
1972
            // s_associatedHandles[] value for the session is now set to TPM_RH_NULL so
1973
            // this will return the authValue associated with TPM_RH_NULL and that is
1974
            // and empty buffer.
1975
            TPM2B_AUTH authValue;
682✔
1976
            //
1977
            // Get the authValue with trailing zeros removed
1978
            EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
682✔
1979

1980
            // Add it to the key
1981
            MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
682✔
1982
        }
1983

1984
    // if the HMAC key size is 0, the response HMAC is computed according to the
1985
    // input HMAC
1986
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
974✔
1987
        {
1988
            hmac->t.size = 0;
127✔
1989
            return;
127✔
1990
        }
1991
    // Start HMAC computation.
1992
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
847✔
1993

1994
    // Add hash components.
1995
    CryptDigestUpdate2B(&hmacState.hashState, &rpHash->b);
847✔
1996
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
847✔
1997
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
847✔
1998

1999
    // Add session attributes.
2000
    buffer      = marshalBuffer;
847✔
2001
    marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL);
847✔
2002
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
847✔
2003

2004
    // Finalize HMAC.
2005
    CryptHmacEnd2B(&hmacState, &hmac->b);
847✔
2006

2007
    return;
847✔
2008
}
2009

2010
//*** UpdateInternalSession()
2011
// This function updates internal sessions by:
2012
// a) restarting session time; and
2013
// b) clearing a policy session since nonce is rolling.
2014
static void UpdateInternalSession(SESSION* session,  // IN: the session structure
978✔
2015
                                  UINT32   i         // IN: session number
2016
                                  )
2017
{
2018
    // If nonce is rolling in a policy session, the policy related data
2019
    // will be re-initialized.
2020
    if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION
978✔
2021
       && IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
165✔
2022
        {
2023
            // When the nonce rolls it starts a new timing interval for the
2024
            // policy session.
2025
            SessionResetPolicyData(session);
121✔
2026
            SessionSetStartTime(session);
121✔
2027
        }
2028
    return;
978✔
2029
}
2030

2031
//*** BuildSingleResponseAuth()
2032
//   Function to compute response HMAC value for a policy or HMAC session.
2033
static TPM2B_NONCE* BuildSingleResponseAuth(
978✔
2034
                                            COMMAND*    command,       // IN: command structure
2035
                                            UINT32      sessionIndex,  // IN: session index to be processed
2036
                                            TPM2B_AUTH* auth           // OUT: authHMAC
2037
                                            )
2038
{
2039
    // Fill in policy/HMAC based session response.
2040
    SESSION* session = SessionGet(s_sessionHandles[sessionIndex]);
978✔
2041
    //
2042
    // If the session is a policy session with isPasswordNeeded SET, the
2043
    // authorization field is empty.
2044
    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
978✔
2045
       && session->attributes.isPasswordNeeded == SET)
165✔
2046
        auth->t.size = 0;
4✔
2047
    else
2048
        // Compute response HMAC.
2049
        ComputeResponseHMAC(command, sessionIndex, session, auth);
974✔
2050

2051
    UpdateInternalSession(session, sessionIndex);
978✔
2052
    return &session->nonceTPM;
978✔
2053
}
2054

2055
//*** UpdateAllNonceTPM()
2056
// Updates TPM nonce for all sessions in command.
2057
static void UpdateAllNonceTPM(COMMAND* command  // IN: controlling structure
5,122✔
2058
                              )
2059
{
2060
    UINT32   i;
5,122✔
2061
    SESSION* session;
5,122✔
2062
    //
2063
    for(i = 0; i < command->sessionNum; i++)
10,718✔
2064
        {
2065
            // If not a PW session, compute the new nonceTPM.
2066
            if(s_sessionHandles[i] != TPM_RS_PW)
5,596✔
2067
                {
2068
                    session = SessionGet(s_sessionHandles[i]);
978✔
2069
                    // Update nonceTPM in both internal session and response.
2070
                    CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
978✔
2071
                }
2072
        }
2073
    return;
5,122✔
2074
}
2075

2076
//*** BuildResponseSession()
2077
// Function to build Session buffer in a response. The authorization data is added
2078
// to the end of command->responseBuffer. The size of the authorization area is
2079
// accumulated in command->authSize.
2080
// When this is called, command->responseBuffer is pointing at the next location
2081
// in the response buffer to be filled. This is where the authorization sessions
2082
// will go, if any. command->parameterSize is the number of bytes that have been
2083
// marshaled as parameters in the output buffer.
2084
TPM_RC
2085
BuildResponseSession(COMMAND* command  // IN: structure that has relevant command
14,469✔
2086
                     //     information
2087
                     )
2088
{
2089
    TPM_RC result = TPM_RC_SUCCESS;
14,469✔
2090

2091
    pAssert(command->authSize == 0);
14,469✔
2092

2093
    // Reset the parameter buffer to point to the start of the parameters so that
2094
    // there is a starting point for any rpHash that might be generated and so there
2095
    // is a place where parameter encryption would start
2096
    command->parameterBuffer = command->responseBuffer - command->parameterSize;
14,469✔
2097

2098
    // Session nonces should be updated before parameter encryption
2099
    if(command->tag == TPM_ST_SESSIONS)
14,469✔
2100
        {
2101
            UpdateAllNonceTPM(command);
5,122✔
2102

2103
            // Encrypt first parameter if applicable. Parameter encryption should
2104
            // happen after nonce update and before any rpHash is computed.
2105
            // If the encrypt session is associated with a handle, the authValue of
2106
            // this handle will be concatenated with sessionKey to generate
2107
            // encryption key, no matter if the handle is the session bound entity
2108
            // or not. The authValue is added to sessionKey only when the authValue
2109
            // is available.
2110
            if(s_encryptSessionIndex != UNDEFINED_INDEX)
5,122✔
2111
                {
2112
                    UINT32     size;
152✔
2113
                    TPM2B_AUTH extraKey;
152✔
2114
                    //
2115
                    extraKey.b.size = 0;
152✔
2116
                    // If this is an authorization session, include the authValue in the
2117
                    // generation of the encryption key
2118
                    if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED)
152✔
2119
                        {
2120
                            EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
102✔
2121
                                               &extraKey);
2122
                        }
2123
                    size = EncryptSize(command->index);
152✔
2124
                    // This function operates on internally-generated data that is
2125
                    // expected to be well-formed for parameter encryption.
2126
                    // In the event that there is a bug elsewhere in the code and the
2127
                    // input data is not well-formed, CryptParameterEncryption will
2128
                    // put the TPM into failure mode instead of allowing the out-of-
2129
                    // band write.
2130
                    CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
152✔
2131
                                             &s_nonceCaller[s_encryptSessionIndex].b,
152✔
2132
                                             command->parameterSize,
2133
                                             (UINT16)size,
2134
                                             &extraKey,
2135
                                             command->parameterBuffer);
2136
                    if(g_inFailureMode)
152✔
2137
                        {
2138
                            result = TPM_RC_FAILURE;
×
2139
                            goto Cleanup;
×
2140
                        }
2141
                }
2142
        }
2143
    // Audit sessions should be processed regardless of the tag because
2144
    // a command with no session may cause a change of the exclusivity state.
2145
    UpdateAuditSessionStatus(command);
14,469✔
2146
#if CC_GetCommandAuditDigest
2147
    // Command Audit
2148
    if(CommandAuditIsRequired(command->index))
14,469✔
2149
        CommandAudit(command);
17✔
2150
#endif
2151
    // Process command with sessions.
2152
    if(command->tag == TPM_ST_SESSIONS)
14,469✔
2153
        {
2154
            UINT32 i;
5,122✔
2155
            //
2156
            pAssert(command->sessionNum > 0);
5,122✔
2157

2158
            // Iterate over each session in the command session area, and create
2159
            // corresponding sessions for response.
2160
            for(i = 0; i < command->sessionNum; i++)
10,718✔
2161
                {
2162
                    TPM2B_NONCE* nonceTPM;
5,596✔
2163
                    TPM2B_DIGEST responseAuth;
5,596✔
2164
                    // Make sure that continueSession is SET on any Password session.
2165
                    // This makes it marginally easier for the management software
2166
                    // to keep track of the closed sessions.
2167
                    if(s_sessionHandles[i] == TPM_RS_PW)
5,596✔
2168
                        {
2169
                            SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession);
4,618✔
2170
                            responseAuth.t.size = 0;
4,618✔
2171
                            nonceTPM            = (TPM2B_NONCE*)&responseAuth;
4,618✔
2172
                        }
2173
                    else
2174
                        {
2175
                            // Compute the response HMAC and get a pointer to the nonce used.
2176
                            // This function will also update the values if needed. Note, the
2177
                            nonceTPM = BuildSingleResponseAuth(command, i, &responseAuth);
978✔
2178
                        }
2179
                    command->authSize +=
11,192✔
2180
                        TPM2B_NONCE_Marshal(nonceTPM, &command->responseBuffer, NULL);
5,596✔
2181
                    command->authSize += TPMA_SESSION_Marshal(
5,596✔
2182
                                                              &s_attributes[i], &command->responseBuffer, NULL);
2183
                    command->authSize +=
11,192✔
2184
                        TPM2B_DIGEST_Marshal(&responseAuth, &command->responseBuffer, NULL);
5,596✔
2185
                    if(!IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
5,596✔
2186
                        SessionFlush(s_sessionHandles[i]);
89✔
2187
                }
2188
        }
2189

2190
 Cleanup:
14,469✔
2191
    return result;
14,469✔
2192
}
2193

2194
//*** SessionRemoveAssociationToHandle()
2195
// This function deals with the case where an entity associated with an authorization
2196
// is deleted during command processing. The primary use of this is to support
2197
// UndefineSpaceSpecial().
2198
void SessionRemoveAssociationToHandle(TPM_HANDLE handle)
2✔
2199
{
2200
    UINT32 i;
2✔
2201
    //
2202
    for(i = 0; i < MAX_SESSION_NUM; i++)
8✔
2203
        {
2204
            if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle))
6✔
2205
                {
2206
                    s_associatedHandles[i] = TPM_RH_NULL;
2✔
2207
                }
2208
        }
2209
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc