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

stefanberger / libtpms / #2037

05 Dec 2025 06:50PM UTC coverage: 77.185% (-0.03%) from 77.213%
#2037

push

travis-ci

web-flow
Merge 73eca8c26 into 4f71e9b45

992 of 1176 new or added lines in 85 files covered. (84.35%)

1748 existing lines in 62 files now uncovered.

36357 of 47104 relevant lines covered (77.18%)

125949.64 hits per line

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

90.51
/src/tpm2/SessionProcess.c
1
// SPDX-License-Identifier: BSD-2-Clause
2

3
//**  Introduction
4
// This file contains the subsystem that process the authorization sessions
5
// including implementation of the Dictionary Attack logic. ExecCommand() uses
6
// ParseSessionBuffer() to process the authorization session area of a command and
7
// BuildResponseSession() to create the authorization session area of a response.
8

9
//**  Includes and Data Definitions
10

11
#define SESSION_PROCESS_C
12

13
#include "Tpm.h"
14
#include "ACT.h"
15
#include "Marshal.h"
16
#include "platform_virtual_nv_fp.h"
17
#if SEC_CHANNEL_SUPPORT
18
#  include "SecChannel_fp.h"
19
#endif  // SEC_CHANNEL_SUPPORT
20

21
//
22
//**  Authorization Support Functions
23
//
24

25
//*** IsDAExempted()
26
// This function indicates if a handle is exempted from DA logic.
27
// A handle is exempted if it is:
28
//  a) a primary seed handle;
29
//  b) an object with noDA bit SET;
30
//  c) an NV Index with TPMA_NV_NO_DA bit SET; or
31
//  d) a PCR handle.
32
//
33
//  Return Type: BOOL
34
//      TRUE(1)         handle is exempted from DA logic
35
//      FALSE(0)        handle is not exempted from DA logic
36
BOOL IsDAExempted(TPM_HANDLE handle  // IN: entity handle
6,560✔
37
)
38
{
39
    BOOL result = FALSE;
6,560✔
40
    //
41
    switch(HandleGetType(handle))
6,560✔
42
    {
43
        case TPM_HT_PERMANENT:
3,727✔
44
            // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
45
            // DA protection.
46
            result = (handle != TPM_RH_LOCKOUT);
3,727✔
47
            break;
3,727✔
48
        // When this function is called, a persistent object will have been loaded
49
        // into an object slot and assigned a transient handle.
50
        case TPM_HT_TRANSIENT:
1,971✔
51
        {
52
            TPMA_OBJECT attributes = ObjectGetPublicAttributes(handle);
1,971✔
53
            result                 = IS_ATTRIBUTE(attributes, TPMA_OBJECT, noDA);
1,971✔
54
            break;
1,971✔
55
        }
56
        case TPM_HT_NV_INDEX:
574✔
57
        {
58
            NV_INDEX* nvIndex = NULL;
574✔
59
            NV_INDEX  ekIndex = {0};
574✔
60
            if(_plat__IsNvVirtualIndex(handle))
574✔
61
            {
NEW
62
                _plat__NvVirtual_PopulateNvIndexInfo(
×
63
                    handle, &ekIndex.publicArea, &ekIndex.authValue);
NEW
64
                nvIndex = &ekIndex;
×
65
            }
66
            else
67
            {
68
                nvIndex = NvGetIndexInfo(handle, NULL);
574✔
69
            }
70
            result = IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, NO_DA);
574✔
71
            break;
574✔
72
        }
73
        case TPM_HT_PCR:
288✔
74
            // PCRs are always exempted from DA.
75
            result = TRUE;
288✔
76
            break;
288✔
77
        default:
78
            break;
79
    }
80
    return result;
6,560✔
81
}
82

83
//*** IncrementLockout()
84
// This function is called after an authorization failure that involves use of
85
// an authValue. If the entity referenced by the handle is not exempt from DA
86
// protection, then the failedTries counter will be incremented.
87
//
88
//  Return Type: TPM_RC
89
//      TPM_RC_AUTH_FAIL    authorization failure that caused DA lockout to increment
90
//      TPM_RC_BAD_AUTH     authorization failure did not cause DA lockout to
91
//                          increment
92
static TPM_RC IncrementLockout(UINT32 sessionIndex)
89✔
93
{
94
    TPM_HANDLE handle        = s_associatedHandles[sessionIndex];
89✔
95
    TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
89✔
96
    SESSION*   session       = NULL;
89✔
97
    //
98
    // Don't increment lockout unless the handle associated with the session
99
    // is DA protected or the session is bound to a DA protected entity.
100
    if(sessionHandle == TPM_RS_PW)
89✔
101
    {
102
        if(IsDAExempted(handle))
78✔
103
            return TPM_RC_BAD_AUTH;
104
    }
105
    else
106
    {
107
        session = SessionGet(sessionHandle);
11✔
108
        pAssert_RC(session);
11✔
109
        // If the session is bound to lockout, then use that as the relevant
110
        // handle. This means that an authorization failure with a bound session
111
        // bound to lockoutAuth will take precedence over any other
112
        // lockout check
113
        if(session->attributes.isLockoutBound == SET)
11✔
UNCOV
114
            handle = TPM_RH_LOCKOUT;
×
115
        if(session->attributes.isDaBound == CLEAR
11✔
116
           && (IsDAExempted(handle) || session->attributes.includeAuth == CLEAR))
11✔
117
            // If the handle was changed to TPM_RH_LOCKOUT, this will not return
118
            // TPM_RC_BAD_AUTH
119
            return TPM_RC_BAD_AUTH;
120
    }
121
    if(handle == TPM_RH_LOCKOUT)
20✔
122
    {
123
        pAssert_RC(gp.lockOutAuthEnabled == TRUE);
4✔
124

125
        // lockout is no longer enabled
126
        gp.lockOutAuthEnabled = FALSE;
4✔
127

128
        // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
129
        // the lockout authorization will be reset at startup.
130
        if(gp.lockoutRecovery != 0)
4✔
131
        {
132
            if(NV_IS_AVAILABLE)
4✔
133
                // Update NV.
134
                NV_SYNC_PERSISTENT(lockOutAuthEnabled);
4✔
135
            else
136
                // No NV access for now. Put the TPM in pending mode.
UNCOV
137
                s_DAPendingOnNV = TRUE;
×
138
        }
139
    }
140
    else
141
    {
142
        if(gp.recoveryTime != 0)
16✔
143
        {
144
            gp.failedTries++;
15✔
145
            if(NV_IS_AVAILABLE)
15✔
146
                // Record changes to NV. NvWrite will SET g_updateNV
147
                NV_SYNC_PERSISTENT(failedTries);
15✔
148
            else
149
                // No NV access for now.  Put the TPM in pending mode.
UNCOV
150
                s_DAPendingOnNV = TRUE;
×
151
        }
152
    }
153
    // Register a DA failure and reset the timers.
154
    DARegisterFailure(handle);
20✔
155

156
    return TPM_RC_AUTH_FAIL;
20✔
157
}
158

159
//*** IsSessionBindEntity()
160
// This function indicates if the entity associated with the handle is the entity,
161
// to which this session is bound. The binding would occur by making the "bind"
162
// parameter in TPM2_StartAuthSession() not equal to TPM_RH_NULL. The binding only
163
// occurs if the session is an HMAC session. The bind value is a combination of
164
// the Name and the authValue of the entity.
165
//
166
//  Return Type: BOOL
167
//      TRUE(1)         handle points to the session start entity
168
//      FALSE(0)        handle does not point to the session start entity
169
static BOOL IsSessionBindEntity(
772✔
170
    TPM_HANDLE associatedHandle,  // IN: handle to be authorized
171
    SESSION*   session            // IN: associated session
172
)
173
{
174
    TPM2B_NAME entity;  // The bind value for the entity
772✔
175
                        //
176
    // If the session is not bound, return FALSE.
177
    if(session->attributes.isBound)
772✔
178
    {
179
        // Compute the bind value for the entity.
180
        SessionComputeBoundEntity(associatedHandle, &entity);
60✔
181

182
        // Compare to the bind value in the session.
183
        return MemoryEqual2B(&entity.b, &session->u1.boundEntity.b);
60✔
184
    }
185
    return FALSE;
186
}
187

188
//*** IsPolicySessionRequired()
189
// Checks if a policy session is required for a command. If a command requires
190
// DUP or ADMIN role authorization, then the handle that requires that role is the
191
// first handle in the command. This simplifies this checking. If a new command
192
// is created that requires multiple ADMIN role authorizations, then it will
193
// have to be special-cased in this function.
194
// A policy session is required if:
195
// a) the command requires the DUP role;
196
// b) the command requires the ADMIN role and the authorized entity
197
//    is an object and its adminWithPolicy bit is SET;
198
// c) the command requires the ADMIN role and the authorized entity
199
//    is a permanent handle or an NV Index; or
200
// d) the authorized entity is a PCR belonging to a policy group, and
201
//    has its policy initialized
202
//  Return Type: BOOL
203
//      TRUE(1)         policy session is required
204
//      FALSE(0)        policy session is not required
205
static BOOL IsPolicySessionRequired(COMMAND_INDEX commandIndex,  // IN: command index
6,436✔
206
                                    UINT32        sessionIndex   // IN: session index
207
)
208
{
209
    AUTH_ROLE role = CommandAuthRole(commandIndex, sessionIndex);
6,436✔
210
    TPM_HT    type = HandleGetType(s_associatedHandles[sessionIndex]);
6,436✔
211
    //
212
    if(role == AUTH_DUP)
6,436✔
213
        return TRUE;
214
    if(role == AUTH_ADMIN)
6,436✔
215
    {
216
        // We allow an exception for ADMIN role in a transient object. If the object
217
        // allows ADMIN role actions with authorization, then policy is not
218
        // required. For all other cases, there is no way to override the command
219
        // requirement that a policy be used
220
        if(type == TPM_HT_TRANSIENT)
284✔
221
        {
222
            OBJECT* object = HandleToObject(s_associatedHandles[sessionIndex]);
271✔
223
            pAssert_BOOL(object != NULL);
271✔
224
            if(!IS_ATTRIBUTE(
271✔
225
                   object->publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy))
226
                return FALSE;
227
        }
228
        return TRUE;
13✔
229
    }
230

231
    if(type == TPM_HT_PCR)
6,152✔
232
    {
233
        if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex]))
276✔
234
        {
UNCOV
235
            TPM2B_DIGEST  policy;
×
UNCOV
236
            TPMI_ALG_HASH policyAlg;
×
UNCOV
237
            policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], &policy);
×
UNCOV
238
            if(policyAlg != TPM_ALG_NULL)
×
UNCOV
239
                return TRUE;
×
240
        }
241
    }
242
    return FALSE;
243
}
244

245
//*** IsAuthValueAvailable()
246
// This function indicates if authValue is available and allowed for USER role
247
// authorization of an entity.
248
//
249
// This function is similar to IsAuthPolicyAvailable() except that it does not
250
// check the size of the authValue as IsAuthPolicyAvailable() does (a null
251
// authValue is a valid authorization, but a null policy is not a valid policy).
252
//
253
// This function does not check that the handle reference is valid or if the entity
254
// is in an enabled hierarchy. Those checks are assumed to have been performed
255
// during the handle unmarshaling.
256
//
257
//  Return Type: BOOL
258
//      TRUE(1)         authValue is available
259
//      FALSE(0)        authValue is not available
260
static BOOL IsAuthValueAvailable(TPM_HANDLE    handle,        // IN: handle of entity
6,396✔
261
                                 COMMAND_INDEX commandIndex,  // IN: command index
262
                                 UINT32        sessionIndex   // IN: session index
263
)
264
{
265
    BOOL result = FALSE;
6,396✔
266
    //
267
    switch(HandleGetType(handle))
6,396✔
268
    {
269
        case TPM_HT_PERMANENT:
3,654✔
270
            switch(handle)
3,654✔
271
            {
272
                    // At this point hierarchy availability has already been
273
                    // checked so primary seed handles are always available here
274
                case TPM_RH_OWNER:
3,654✔
275
                case TPM_RH_ENDORSEMENT:
276
                case TPM_RH_PLATFORM:
277
#if VENDOR_PERMANENT_AUTH_ENABLED == YES
278
                    // This vendor defined handle associated with the
279
                    // manufacturer's shared secret
280
                case VENDOR_PERMANENT_AUTH_HANDLE:
281
#endif
282
                    // The DA checking has been performed on LockoutAuth but we
283
                    // bypass the DA logic if we are using lockout policy. The
284
                    // policy would allow execution to continue an lockoutAuth
285
                    // could be used, even if direct use of lockoutAuth is disabled
286
                case TPM_RH_LOCKOUT:
287
                    // NullAuth is always available.
288
                case TPM_RH_NULL:
289
                    result = TRUE;
3,654✔
290
                    break;
3,654✔
291

292
#ifndef __ACT_DISABLED        // libtpms changed
293
                    FOR_EACH_ACT(CASE_ACT_HANDLE)
294
                    {
295
                        // The ACT auth value is not available if the platform is disabled
296
                        result = g_phEnable == SET;
297
                        break;
298
                    }
299
#endif  // ACT_SUPPORT
300

301
                default:
302
                    // Otherwise authValue is not available.
303
                    break;
304
            }
305
            break;
306
        case TPM_HT_TRANSIENT:
1,960✔
307
            // A persistent object has already been loaded and the internal
308
            // handle changed.
309
            {
310
                OBJECT*     object;
1,960✔
311
                TPMA_OBJECT attributes;
1,960✔
312
                //
313
                object = HandleToObject(handle);
1,960✔
314
                pAssert_BOOL(object != NULL);
1,960✔
315
                attributes = object->publicArea.objectAttributes;
1,960✔
316

317
                // authValue is always available for a sequence object.
318
                // An alternative for this is to
319
                // SET_ATTRIBUTE(object->publicArea, TPMA_OBJECT, userWithAuth) when the
320
                // sequence is started.
321
                if(ObjectIsSequence(object))
1,960✔
322
                {
323
                    result = TRUE;
324
                    break;
325
                }
326
                // authValue is available for an object if it has its sensitive
327
                // portion loaded and
328
                //  a) userWithAuth bit is SET, or
329
                //  b) ADMIN role is required
330
                if(object->attributes.publicOnly == CLEAR
1,851✔
331
                   && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, userWithAuth)
1,851✔
332
                       || (CommandAuthRole(commandIndex, sessionIndex) == AUTH_ADMIN
8✔
UNCOV
333
                           && !IS_ATTRIBUTE(
×
334
                               attributes, TPMA_OBJECT, adminWithPolicy))))
335
                    result = TRUE;
336
            }
337
            break;
338
        case TPM_HT_NV_INDEX:
506✔
339
            // NV Index.
340
            {
341
                NV_REF    locator;
506✔
342
                NV_INDEX* nvIndex = NULL;
506✔
343
                TPMA_NV   nvAttributes;
506✔
344
                //
345

346
                if(_plat__IsNvVirtualIndex(handle))
506✔
347
                {
NEW
348
                    NV_INDEX tempIndex = {0};
×
NEW
349
                    _plat__NvVirtual_PopulateNvIndexInfo(
×
350
                        handle, &tempIndex.publicArea, &tempIndex.authValue);
NEW
351
                    nvIndex = &tempIndex;
×
352

NEW
353
                    locator = (NV_REF)0;
×
354
                }
355
                else
356
                {
357
                    nvIndex = NvGetIndexInfo(handle, &locator);
506✔
358
                }
359
                pAssert_BOOL(nvIndex != 0);
506✔
360

361
                nvAttributes = nvIndex->publicArea.attributes;
506✔
362

363
                if(IsWriteOperation(commandIndex))
506✔
364
                {
365
                    // AuthWrite can't be set for a PIN index
366
                    if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHWRITE))
224✔
367
                        result = TRUE;
220✔
368
                }
369
                else
370
                {
371
                    // A "read" operation
372
                    // For a PIN Index, the authValue is available as long as the
373
                    // Index has been written and the pinCount is less than pinLimit
374
                    if(IsNvPinFailIndex(nvAttributes)
282✔
375
                       || IsNvPinPassIndex(nvAttributes))
282✔
376
                    {
377
                        NV_PIN pin;
32✔
378
                        if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
32✔
379
                            break;  // return false
380

381
                        if(locator == (NV_REF)0)
31✔
382
                            break;  // return false
383

384
                        // get the index values
385
                        pin.intVal = NvGetUINT64Data(nvIndex, locator);
31✔
386
                        if(pin.pin.pinCount < pin.pin.pinLimit)
31✔
387
                            result = TRUE;
21✔
388
                    }
389
                    // For non-PIN Indexes, need to allow use of the authValue
390
                    else if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHREAD))
250✔
391
                        result = TRUE;
246✔
392
                }
393
            }
394
            break;
505✔
395
        case TPM_HT_PCR:
276✔
396
            // PCR handle.
397
            // authValue is always allowed for PCR
398
            result = TRUE;
276✔
399
            break;
276✔
400
        default:
401
            // Otherwise, authValue is not available
402
            break;
403
    }
404
    return result;
6,396✔
405
}
406

407
//*** IsAuthPolicyAvailable()
408
// This function indicates if an authPolicy is available and allowed.
409
//
410
// This function does not check that the handle reference is valid or if the entity
411
// is in an enabled hierarchy. Those checks are assumed to have been performed
412
// during the handle unmarshaling.
413
//
414
//  Return Type: BOOL
415
//      TRUE(1)         authPolicy is available
416
//      FALSE(0)        authPolicy is not available
417
static BOOL IsAuthPolicyAvailable(TPM_HANDLE    handle,        // IN: handle of entity
208✔
418
                                  COMMAND_INDEX commandIndex,  // IN: command index
419
                                  UINT32        sessionIndex   // IN: session index
420
)
421
{
422
    BOOL result = FALSE;
208✔
423
    //
424
    switch(HandleGetType(handle))
208✔
425
    {
426
        case TPM_HT_PERMANENT:
7✔
427
            switch(handle)
7✔
428
            {
429
                // At this point hierarchy availability has already been checked.
UNCOV
430
                case TPM_RH_OWNER:
×
UNCOV
431
                    if(gp.ownerPolicy.t.size != 0)
×
UNCOV
432
                        result = TRUE;
×
433
                    break;
UNCOV
434
                case TPM_RH_ENDORSEMENT:
×
UNCOV
435
                    if(gp.endorsementPolicy.t.size != 0)
×
UNCOV
436
                        result = TRUE;
×
437
                    break;
438
                case TPM_RH_PLATFORM:
7✔
439
                    if(gc.platformPolicy.t.size != 0)
7✔
440
                        result = TRUE;
7✔
441
                    break;
442
#if ACT_SUPPORT || 1        // libtpms changed
443

444
#  define ACT_GET_POLICY(N)                     \
445
      case TPM_RH_ACT_##N:                      \
446
          if(go.ACT_##N.authPolicy.t.size != 0) \
447
              result = TRUE;                    \
448
          break;
449

450
                    FOR_EACH_ACT(ACT_GET_POLICY)
451
#endif  // ACT_SUPPORT
452

UNCOV
453
                case TPM_RH_LOCKOUT:
×
UNCOV
454
                    if(gp.lockoutPolicy.t.size != 0)
×
UNCOV
455
                        result = TRUE;
×
456
                    break;
457
                default:
458
                    break;
459
            }
460
            break;
461
        case TPM_HT_TRANSIENT:
163✔
462
        {
463
            // Object handle.
464
            // An evict object would already have been loaded and given a
465
            // transient object handle by this point.
466
            OBJECT* object = HandleToObject(handle);
163✔
467
            pAssert_BOOL(object != NULL);
163✔
468
            // Policy authorization is not available for an object with only
469
            // public portion loaded.
470
            if(object->attributes.publicOnly == CLEAR)
163✔
471
            {
472
                // Policy authorization is always available for an object but
473
                // is never available for a sequence.
474
                if(!ObjectIsSequence(object))
163✔
475
                    result = TRUE;
163✔
476
            }
477
            break;
478
        }
479
        case TPM_HT_NV_INDEX:
38✔
480
            // An NV Index.
481
            {
482
                NV_INDEX* nvIndex      = NvGetIndexInfo(handle, NULL);
38✔
483
                TPMA_NV   nvAttributes = nvIndex->publicArea.attributes;
38✔
484
                //
485
                // If the policy size is not zero, check if policy can be used.
486
                if(nvIndex->publicArea.authPolicy.t.size != 0)
38✔
487
                {
488
                    // If policy session is required for this handle, always
489
                    // uses policy regardless of the attributes bit setting
490
                    if(IsPolicySessionRequired(commandIndex, sessionIndex))
38✔
491
                        result = TRUE;
492
                    // Otherwise, the presence of the policy depends on the NV
493
                    // attributes.
494
                    else if(IsWriteOperation(commandIndex))
27✔
495
                    {
496
                        if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYWRITE))
19✔
497
                            result = TRUE;
19✔
498
                    }
499
                    else
500
                    {
501
                        if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYREAD))
8✔
502
                            result = TRUE;
8✔
503
                    }
504
                }
505
            }
506
            break;
UNCOV
507
        case TPM_HT_PCR:
×
508
            // PCR handle.
UNCOV
509
            if(PCRPolicyIsAvailable(handle))
×
UNCOV
510
                result = TRUE;
×
511
            break;
512
        default:
513
            break;
514
    }
515
    return result;
208✔
516
}
517

518
//**  Session Parsing Functions
519

520
//*** ClearCpRpHashes()
521
void ClearCpRpHashes(COMMAND* command)
16,851✔
522
{
523
    // The macros expand according to the implemented hash algorithms. An IDE may
524
    // complain that COMMAND does not contain SHA1CpHash or SHA1RpHash because of the
525
    // complexity of the macro expansion where the data space is defined; but, if SHA1
526
    // is implemented, it actually does  and the compiler is happy.
527
#define CLEAR_CP_HASH(HASH, Hash) command->Hash##CpHash.b.size = 0;
528
    FOR_EACH_HASH(CLEAR_CP_HASH)
16,851✔
529
#define CLEAR_RP_HASH(HASH, Hash) command->Hash##RpHash.b.size = 0;
530
    FOR_EACH_HASH(CLEAR_RP_HASH)
16,851✔
531
}
16,851✔
532

533
//*** GetCpHashPointer()
534
// Function to get a pointer to the cpHash of the command
535
static TPM2B_DIGEST* GetCpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,055✔
536
{
537
    TPM2B_DIGEST* retVal;
1,055✔
538
//
539
// Define the macro that will expand for each implemented algorithm in the switch
540
// statement below.
541
#define GET_CP_HASH_POINTER(HASH, Hash)                 \
542
    case ALG_##HASH##_VALUE:                            \
543
        retVal = (TPM2B_DIGEST*)&command->Hash##CpHash; \
544
        break;
545

546
    switch(hashAlg)
1,055✔
547
    {
548
        // For each implemented hash, this will expand as defined above
549
        // by GET_CP_HASH_POINTER. Your IDE may complain that
550
        // 'struct "COMMAND" has no field "SHA1CpHash"' but the compiler says
551
        // it does, so...
552
        FOR_EACH_HASH(GET_CP_HASH_POINTER)
1,055✔
553
        default:
554
            retVal = NULL;
555
            break;
556
    }
557
    return retVal;
1,055✔
558
}
559

560
//*** GetRpHashPointer()
561
// Function to get a pointer to the RpHash of the command
562
static TPM2B_DIGEST* GetRpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,026✔
563
{
564
    TPM2B_DIGEST* retVal;
1,026✔
565
//
566
// Define the macro that will expand for each implemented algorithm in the switch
567
// statement below.
568
#define GET_RP_HASH_POINTER(HASH, Hash)                 \
569
    case ALG_##HASH##_VALUE:                            \
570
        retVal = (TPM2B_DIGEST*)&command->Hash##RpHash; \
571
        break;
572

573
    switch(hashAlg)
1,026✔
574
    {
575
        // For each implemented hash, this will expand as defined above
576
        // by GET_RP_HASH_POINTER. Your IDE may complain that
577
        // 'struct "COMMAND" has no field 'SHA1RpHash'" but the compiler says
578
        // it does, so...
579
        FOR_EACH_HASH(GET_RP_HASH_POINTER)
1,026✔
580
        default:
581
            retVal = NULL;
582
            break;
583
    }
584
    return retVal;
1,026✔
585
}
586

587
//*** ComputeCpHash()
588
// This function computes the cpHash as defined in Part 2 and described in Part 1.
589
static TPM2B_DIGEST* ComputeCpHash(COMMAND* command,  // IN: command parsing structure
1,003✔
590
                                   TPMI_ALG_HASH hashAlg  // IN: hash algorithm
591
)
592
{
593
    UINT32        i;
1,003✔
594
    HASH_STATE    hashState;
1,003✔
595
    TPM2B_NAME    name;
1,003✔
596
    TPM2B_DIGEST* cpHash;
1,003✔
597
    //
598
    // cpHash = hash(commandCode [ || authName1
599
    //                           [ || authName2
600
    //                           [ || authName 3 ]]]
601
    //                           [ || parameters])
602
    // A cpHash can contain just a commandCode only if the lone session is
603
    // an audit session.
604
    // Get pointer to the hash value
605
    cpHash = GetCpHashPointer(command, hashAlg);
1,003✔
606
    if(cpHash->t.size == 0)
1,003✔
607
    {
608
        cpHash->t.size = CryptHashStart(&hashState, hashAlg);
726✔
609
        //  Add commandCode.
610
        CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
726✔
611
        //  Add authNames for each of the handles.
612
        for(i = 0; i < command->handleNum; i++)
2,553✔
613
            CryptDigestUpdate2B(&hashState,
2,202✔
614
                                &EntityGetName(command->handles[i], &name)->b);
1,101✔
615
        //  Add the parameters.
616
        CryptDigestUpdate(
726✔
617
            &hashState, command->parameterSize, command->parameterBuffer);
726✔
618
        //  Complete the hash.
619
        CryptHashEnd2B(&hashState, &cpHash->b);
726✔
620
    }
621
    return cpHash;
1,003✔
622
}
623

624
//*** GetCpHash()
625
// This function is used to access a precomputed cpHash.
626
static TPM2B_DIGEST* GetCpHash(COMMAND* command, TPMI_ALG_HASH hashAlg)
52✔
627
{
628
    TPM2B_DIGEST* cpHash = GetCpHashPointer(command, hashAlg);
52✔
629
    //
630
    pAssert_NULL(cpHash && cpHash->t.size != 0);
52✔
631
    return cpHash;
52✔
632
}
633

634
//*** CompareTemplateHash()
635
// This function computes the template hash and compares it to the session
636
// templateHash. It is the hash of the second parameter
637
// assuming that the command is TPM2_Create(), TPM2_CreatePrimary(), or
638
// TPM2_CreateLoaded()
639
//  Return Type: BOOL
640
//      TRUE(1)         template hash equal to session->templateHash
641
//      FALSE(0)        template hash not equal to session->templateHash
642
static BOOL CompareTemplateHash(COMMAND* command,  // IN: parsing structure
3✔
643
                                SESSION* session   // IN: session data
644
)
645
{
646
    BYTE*        pBuffer = command->parameterBuffer;
3✔
647
    INT32        pSize   = command->parameterSize;
3✔
648
    TPM2B_DIGEST tHash;
3✔
649
    UINT16       size;
3✔
650
    //
651
    // Only try this for the three commands for which it is intended
652
    if(command->code != TPM_CC_Create && command->code != TPM_CC_CreatePrimary
3✔
653
#if CC_CreateLoaded
654
       && command->code != TPM_CC_CreateLoaded
1✔
655
#endif
656
    )
657
        return FALSE;
658
    // Assume that the first parameter is a TPM2B and unmarshal the size field
659
    // Note: this will not affect the parameter buffer and size in the calling
660
    // function.
661
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
662
        return FALSE;
663
    // reduce the space in the buffer.
664
    // NOTE: this could make pSize go negative if the parameters are not correct but
665
    // the unmarshaling code does not try to unmarshal if the remaining size is
666
    // negative.
667
    pSize -= size;
3✔
668

669
    // Advance the pointer
670
    pBuffer += size;
3✔
671

672
    // Get the size of what should be the template
673
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
674
        return FALSE;
675
    // See if this is reasonable
676
    if(size > pSize)
3✔
677
        return FALSE;
678
    // Hash the template data
679
    tHash.t.size = CryptHashBlock(
6✔
680
        session->authHashAlg, size, pBuffer, sizeof(tHash.t.buffer), tHash.t.buffer);
3✔
681
    return (MemoryEqual2B(&session->u1.templateHash.b, &tHash.b));
3✔
682
}
683

684
//*** CompareNameHash()
685
// This function computes the name hash and compares it to the nameHash in the
686
// session data, returning true if they are equal.
687
BOOL CompareNameHash(COMMAND* command,  // IN: main parsing structure
3✔
688
                     SESSION* session   // IN: session structure with nameHash
689
)
690
{
691
    HASH_STATE   hashState;
3✔
692
    TPM2B_DIGEST nameHash;
3✔
693
    UINT32       i;
3✔
694
    TPM2B_NAME   name;
3✔
695
    //
696
    nameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
697
    //  Add names.
698
    for(i = 0; i < command->handleNum; i++)
8✔
699
        CryptDigestUpdate2B(&hashState,
10✔
700
                            &EntityGetName(command->handles[i], &name)->b);
5✔
701
    //  Complete hash.
702
    CryptHashEnd2B(&hashState, &nameHash.b);
3✔
703
    // and compare
704
    return MemoryEqual(
6✔
705
        session->u1.nameHash.t.buffer, nameHash.t.buffer, nameHash.t.size);
3✔
706
}
707

708
//*** CompareParametersHash()
709
// This function computes the parameters hash and compares it to the pHash in
710
// the session data, returning true if they are equal.
711
BOOL CompareParametersHash(COMMAND* command,  // IN: main parsing structure
3✔
712
                           SESSION* session   // IN: session structure with pHash
713
)
714
{
715
    HASH_STATE   hashState;
3✔
716
    TPM2B_DIGEST pHash;
3✔
717
    //
718
    pHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
719
    //  Add commandCode.
720
    CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
3✔
721
    //  Add the parameters.
722
    CryptDigestUpdate(&hashState, command->parameterSize, command->parameterBuffer);
3✔
723
    //  Complete hash.
724
    CryptHashEnd2B(&hashState, &pHash.b);
3✔
725
    // and compare
726
    return MemoryEqual2B(&session->u1.pHash.b, &pHash.b);
3✔
727
}
728

729
#if SEC_CHANNEL_SUPPORT
730
//*** CompareScKeyNameHash()
731
// This function computes the secure channel key name hash (from the requester and/or TPM key
732
// used to establish the secure channel session) and compares it to the scKeyNameHash in the
733
// session data, returning true if they are equal.
734
BOOL CompareScKeyNameHash(
735
    SESSION*    session,     // IN: session structure
736
    TPM2B_NAME* reqKeyName,  // IN: requester secure channel key name
737
    TPM2B_NAME* tpmKeyName   // IN: TPM secure channel key name
738
)
739
{
740
    HASH_STATE   hashState;
741
    TPM2B_DIGEST scKeyNameHash;
742
    UINT16       zeroSize = 0x0000;
743

744
    // Compute secure channel key name hash
745
    // scKeyNameHash = hash(reqKeyName.size || reqKeyName.name || tpmKeyName.size || tpmKeyName.name)
746
    //  Start hash
747
    scKeyNameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
748

749
    //  Include reqKeyName if it needs to be checked, otherwise include Empty Buffer
750
    if(session->attributes.checkReqKey)
751
    {
752
        //  Add reqKeyName.size
753
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), reqKeyName->t.size);
754

755
        //  Add reqKeyName.name
756
        CryptDigestUpdate2B(&hashState, &reqKeyName->b);
757
    }
758
    else
759
    {
760
        //  Add zero size
761
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
762
    }
763

764
    //  Include tpmKeyName if it needs to be checked, otherwise include Empty Buffer
765
    if(session->attributes.checkTpmKey)
766
    {
767
        //  Add tpmKeyName.size
768
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), tpmKeyName->t.size);
769

770
        //  Add tpmKeyName.name
771
        CryptDigestUpdate2B(&hashState, &tpmKeyName->b);
772
    }
773
    else
774
    {
775
        //  Add zero size
776
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
777
    }
778

779
    //  Complete hash
780
    CryptHashEnd2B(&hashState, &scKeyNameHash.b);
781

782
    // and compare
783
    return MemoryEqual(session->scKeyNameHash.t.buffer,
784
                       scKeyNameHash.t.buffer,
785
                       scKeyNameHash.t.size);
786
}
787
#endif  // SEC_CHANNEL_SUPPORT
788

789
//*** CheckPWAuthSession()
790
// This function validates the authorization provided in a PWAP session. It
791
// compares the input value to authValue of the authorized entity. Argument
792
// sessionIndex is used to get handles handle of the referenced entities from
793
// s_inputAuthValues[] and s_associatedHandles[].
794
//
795
//  Return Type: TPM_RC
796
//        TPM_RC_AUTH_FAIL          authorization fails and increments DA failure
797
//                                  count
798
//        TPM_RC_BAD_AUTH           authorization fails but DA does not apply
799
//
800
static TPM_RC CheckPWAuthSession(
5,607✔
801
    UINT32 sessionIndex  // IN: index of session to be processed
802
)
803
{
804
    TPM2B_AUTH authValue;
5,607✔
805
    TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex];
5,607✔
806
    //
807
    // Strip trailing zeros from the password.
808
    MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]);
5,607✔
809

810
    // Get the authValue with trailing zeros removed
811
    EntityGetAuthValue(associatedHandle, &authValue);
5,607✔
812

813
    // Success if the values are identical.
814
    if(MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &authValue.b))
5,607✔
815
    {
816
        return TPM_RC_SUCCESS;
817
    }
818
    else  // if the digests are not identical
819
    {
820
        // Invoke DA protection if applicable.
821
        return IncrementLockout(sessionIndex);
79✔
822
    }
823
}
824

825
//*** ComputeCommandHMAC()
826
// This function computes the HMAC for an authorization session in a command.
827
/*(See part 1 specification -- this tag keeps this comment from showing up in
828
// merged document which is probably good because this comment doesn't look right.
829
//      The sessionAuth value
830
//      authHMAC := HMACsHash((sessionKey | authValue),
831
//                  (pHash | nonceNewer | nonceOlder  | nonceTPMencrypt-only
832
//                   | nonceTPMaudit   | sessionAttributes))
833
// Where:
834
//      HMACsHash()     The HMAC algorithm using the hash algorithm specified
835
//                      when the session was started.
836
//
837
//      sessionKey      A value that is computed in a protocol-dependent way,
838
//                      using KDFa. When used in an HMAC or KDF, the size field
839
//                      for this value is not included.
840
//
841
//      authValue       A value that is found in the sensitive area of an entity.
842
//                      When used in an HMAC or KDF, the size field for this
843
//                      value is not included.
844
//
845
//      pHash           Hash of the command (cpHash) using the session hash.
846
//                      When using a pHash in an HMAC computation, only the
847
//                      digest is used.
848
//
849
//      nonceNewer      A value that is generated by the entity using the
850
//                      session. A new nonce is generated on each use of the
851
//                      session. For a command, this will be nonceCaller.
852
//                      When used in an HMAC or KDF, the size field is not used.
853
//
854
//      nonceOlder      A TPM2B_NONCE that was received the previous time the
855
//                      session was used. For a command, this is nonceTPM.
856
//                      When used in an HMAC or KDF, the size field is not used.
857
//
858
//      nonceTPMdecrypt     The nonceTPM of the decrypt session is included in
859
//                          the HMAC, but only in the command.
860
//
861
//      nonceTPMencrypt     The nonceTPM of the encrypt session is included in
862
//                          the HMAC but only in the command.
863
//
864
//      sessionAttributes   A byte indicating the attributes associated with the
865
//                          particular use of the session.
866
*/
867
static TPM_RC ComputeCommandHMAC(
1,028✔
868
    COMMAND*      command,       // IN: primary control structure
869
    UINT32        sessionIndex,  // IN: index of session to be processed
870
    TPM2B_DIGEST* hmac           // OUT: authorization HMAC
871
)
872
{
873
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1,028✔
874
    TPM2B_KEY    key;
1,028✔
875
    BYTE         marshalBuffer[sizeof(TPMA_SESSION)];
1,028✔
876
    BYTE*        buffer;
1,028✔
877
    UINT32       marshalSize;
1,028✔
878
    HMAC_STATE   hmacState;
1,028✔
879
    TPM2B_NONCE* nonceDecrypt;
1,028✔
880
    TPM2B_NONCE* nonceEncrypt;
1,028✔
881
    SESSION*     session;
1,028✔
882
    //
883
    nonceDecrypt = NULL;
1,028✔
884
    nonceEncrypt = NULL;
1,028✔
885

886
    // Determine if extra nonceTPM values are going to be required.
887
    // If this is the first session (sessionIndex = 0) and it is an authorization
888
    // session that uses an HMAC, then check if additional session nonces are to be
889
    // included.
890
    if(sessionIndex == 0 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
1,028✔
891
    {
892
        // If there is a decrypt session and if this is not the decrypt session,
893
        // then an extra nonce may be needed.
894
        if(s_decryptSessionIndex != UNDEFINED_INDEX
773✔
895
           && s_decryptSessionIndex != sessionIndex)
160✔
896
        {
897
            // Will add the nonce for the decrypt session.
898
            SESSION* decryptSession =
84✔
899
                SessionGet(s_sessionHandles[s_decryptSessionIndex]);
84✔
900
            pAssert_RC(decryptSession != NULL);
84✔
901
            nonceDecrypt = &decryptSession->nonceTPM;
84✔
902
        }
903
        // Now repeat for the encrypt session.
904
        if(s_encryptSessionIndex != UNDEFINED_INDEX
773✔
905
           && s_encryptSessionIndex != sessionIndex
152✔
906
           && s_encryptSessionIndex != s_decryptSessionIndex)
84✔
907
        {
908
            // Have to have the nonce for the encrypt session.
909
            SESSION* encryptSession =
64✔
910
                SessionGet(s_sessionHandles[s_encryptSessionIndex]);
64✔
911
            pAssert_RC(encryptSession != NULL);
64✔
912
            nonceEncrypt = &encryptSession->nonceTPM;
64✔
913
        }
914
    }
915

916
    // Continue with the HMAC processing.
917
    session = SessionGet(s_sessionHandles[sessionIndex]);
1,028✔
918
    pAssert_RC(session != NULL);
1,028✔
919

920
    // Generate HMAC key.
921
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1,028✔
922

923
    // Check if the session has an associated handle and if the associated entity
924
    // is the one to which the session is bound. If not, add the authValue of
925
    // this entity to the HMAC key.
926
    // If the session is bound to the object or the session is a policy session
927
    // with no authValue required, do not include the authValue in the HMAC key.
928
    // Note: For a policy session, its isBound attribute is CLEARED.
929
    //
930
    // Include the entity authValue if it is needed
931
    if(session->attributes.includeAuth == SET)
1,028✔
932
    {
933
        TPM2B_AUTH authValue;
735✔
934
        // Get the entity authValue with trailing zeros removed
935
        EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
735✔
936
        // add the authValue to the HMAC key
937
        MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
735✔
938
    }
939
    // if the HMAC key size is 0, a NULL string HMAC is allowed
940
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
1,028✔
941
    {
942
        hmac->t.size = 0;
129✔
943
        return TPM_RC_SUCCESS;
129✔
944
    }
945
    // Start HMAC
946
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
899✔
947

948
    //  Add cpHash
949
    CryptDigestUpdate2B(&hmacState.hashState,
1,798✔
950
                        &ComputeCpHash(command, session->authHashAlg)->b);
899✔
951
    //  Add nonces as required
952
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
899✔
953
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
899✔
954
    if(nonceDecrypt != NULL)
899✔
955
        CryptDigestUpdate2B(&hmacState.hashState, &nonceDecrypt->b);
84✔
956
    if(nonceEncrypt != NULL)
899✔
957
        CryptDigestUpdate2B(&hmacState.hashState, &nonceEncrypt->b);
64✔
958
    //  Add sessionAttributes
959
    buffer      = marshalBuffer;
899✔
960
    marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), &buffer, NULL);
899✔
961
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
899✔
962
    // Complete the HMAC computation
963
    CryptHmacEnd2B(&hmacState, &hmac->b);
899✔
964

965
    return TPM_RC_SUCCESS;
899✔
966
}
967

968
//*** CheckSessionHMAC()
969
// This function checks the HMAC of in a session. It uses ComputeCommandHMAC()
970
// to compute the expected HMAC value and then compares the result with the
971
// HMAC in the authorization session. The authorization is successful if they
972
// are the same.
973
//
974
// If the authorizations are not the same, IncrementLockout() is called. It will
975
// return TPM_RC_AUTH_FAIL if the failure caused the failureCount to increment.
976
// Otherwise, it will return TPM_RC_BAD_AUTH.
977
//
978
//  Return Type: TPM_RC
979
//      TPM_RC_AUTH_FAIL        authorization failure caused failureCount increment
980
//      TPM_RC_BAD_AUTH         authorization failure did not cause failureCount
981
//                              increment
982
//
983
static TPM_RC CheckSessionHMAC(
1,028✔
984
    COMMAND* command,      // IN: primary control structure
985
    UINT32   sessionIndex  // IN: index of session to be processed
986
)
987
{
988
    TPM2B_DIGEST hmac;  // authHMAC for comparing
1,028✔
989
                        //
990
    // Compute authHMAC
991
    TPM_RC result = ComputeCommandHMAC(command, sessionIndex, &hmac);
1,028✔
992
    if(result != TPM_RC_SUCCESS)
1,028✔
993
        return result;
994

995
    // Compare the input HMAC with the authHMAC computed above.
996
    if(!MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &hmac.b))
1,028✔
997
    {
998
        // If an HMAC session has a failure, invoke the anti-hammering
999
        // if it applies to the authorized entity or the session.
1000
        // Otherwise, just indicate that the authorization is bad.
1001
        return IncrementLockout(sessionIndex);
10✔
1002
    }
1003
    return TPM_RC_SUCCESS;
1004
}
1005

1006
//*** CheckPolicyAuthSession()
1007
//  This function is used to validate the authorization in a policy session.
1008
//  This function performs the following comparisons to see if a policy
1009
//  authorization is properly provided. The check are:
1010
//  a) compare policyDigest in session with authPolicy associated with
1011
//     the entity to be authorized;
1012
//  b) compare timeout if applicable;
1013
//  c) compare commandCode if applicable;
1014
//  d) compare cpHash if applicable; and
1015
//  e) see if PCR values have changed since computed.
1016
//
1017
// If all the above checks succeed, the handle is authorized.
1018
// The order of these comparisons is not important because any failure will
1019
// result in the same error code.
1020
//
1021
//  Return Type: TPM_RC
1022
//      TPM_RC_PCR_CHANGED          PCR value is not current
1023
//      TPM_RC_POLICY_FAIL          policy session fails
1024
//      TPM_RC_LOCALITY             command locality is not allowed
1025
//      TPM_RC_POLICY_CC            CC doesn't match
1026
//      TPM_RC_EXPIRED              policy session has expired
1027
//      TPM_RC_PP                   PP is required but not asserted
1028
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
1029
//      TPM_RC_NV_RATE              NV is rate limiting
1030
//      TPM_RC_CHANNEL              No secure channel is active
1031
//      TPM_RC_CHANNEL_KEY          Secure channel key is incorrect
1032
static TPM_RC CheckPolicyAuthSession(
208✔
1033
    COMMAND* command,      // IN: primary parsing structure
1034
    UINT32   sessionIndex  // IN: index of session to be processed
1035
)
1036
{
1037
    SESSION*      session;
208✔
1038
    TPM2B_DIGEST  authPolicy;
208✔
1039
    TPMI_ALG_HASH policyAlg;
208✔
1040
    UINT8         locality;
208✔
1041
    //
1042
    // Initialize pointer to the authorization session.
1043
    session = SessionGet(s_sessionHandles[sessionIndex]);
208✔
1044
    pAssert_RC(session != NULL);
208✔
1045

1046
    // If the command is TPM2_PolicySecret(), make sure that
1047
    // either password or authValue is required
1048
    if(command->code == TPM_CC_PolicySecret
208✔
1049
       && session->attributes.isPasswordNeeded == CLEAR
UNCOV
1050
       && session->attributes.isAuthValueNeeded == CLEAR)
×
1051
        return TPM_RC_MODE;
1052
    // See if the PCR counter for the session is still valid.
1053
    if(!SessionPCRValueIsCurrent(session))
208✔
1054
        return TPM_RC_PCR_CHANGED;
1055
    // Get authPolicy.
1056
    policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], &authPolicy);
207✔
1057
    // Compare authPolicy.
1058
    if(!MemoryEqual2B(&session->u2.policyDigest.b, &authPolicy.b))
207✔
1059
        return TPM_RC_POLICY_FAIL;
1060
    // Policy is OK so check if the other factors are correct
1061

1062
    // Compare policy hash algorithm.
1063
    if(policyAlg != session->authHashAlg)
173✔
1064
        return TPM_RC_POLICY_FAIL;
1065

1066
    // Compare timeout.
1067
    if(session->timeout != 0)
173✔
1068
    {
1069
        // Cannot compare time if clock stop advancing.  An TPM_RC_NV_UNAVAILABLE
1070
        // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that
1071
        // a new nonce will be created just that, because TPM time can't advance
1072
        // we can't do time-based operations.
1073
        RETURN_IF_NV_IS_NOT_AVAILABLE;
11✔
1074

1075
        if((session->timeout < g_time) || (session->epoch != g_timeEpoch))
11✔
1076
            return TPM_RC_EXPIRED;
1077
    }
1078
    // If command code is provided it must match
1079
    if(session->commandCode != 0)
173✔
1080
    {
1081
        if(session->commandCode != command->code)
91✔
1082
            return TPM_RC_POLICY_CC;
1083
    }
1084
    else
1085
    {
1086
        // If command requires a DUP or ADMIN authorization, the session must have
1087
        // command code set.
1088
        AUTH_ROLE role = CommandAuthRole(command->index, sessionIndex);
82✔
1089
        if(role == AUTH_ADMIN || role == AUTH_DUP)
82✔
1090
            return TPM_RC_POLICY_FAIL;
1091
    }
1092
    // Check command locality.
1093
    {
1094
        BYTE  sessionLocality[sizeof(TPMA_LOCALITY)];
170✔
1095
        BYTE* buffer = sessionLocality;
170✔
1096

1097
        // Get existing locality setting in canonical form
1098
        sessionLocality[0] = 0;
170✔
1099
        TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
170✔
1100

1101
        // See if the locality has been set
1102
        if(sessionLocality[0] != 0)
170✔
1103
        {
1104
            // If so, get the current locality
UNCOV
1105
            locality = _plat__LocalityGet();
×
UNCOV
1106
            if(locality < 5)
×
1107
            {
UNCOV
1108
                if(((sessionLocality[0] & (1 << locality)) == 0)
×
UNCOV
1109
                   || sessionLocality[0] > 31)
×
UNCOV
1110
                    return TPM_RC_LOCALITY;
×
1111
            }
UNCOV
1112
            else if(locality > 31)
×
1113
            {
UNCOV
1114
                if(sessionLocality[0] != locality)
×
1115
                    return TPM_RC_LOCALITY;
1116
            }
1117
            else
1118
            {
1119
                // Could throw an assert here but a locality error is just
1120
                // as good. It just means that, whatever the locality is, it isn't
1121
                // the locality requested so...
1122
                return TPM_RC_LOCALITY;
1123
            }
1124
        }
1125
    }  // end of locality check
1126
    // Check physical presence.
1127
    if(session->attributes.isPPRequired == SET && !_plat__PhysicalPresenceAsserted())
170✔
1128
        return TPM_RC_PP;
1129
    // Compare cpHash/nameHash/pHash/templateHash if defined.
1130
    if(session->u1.cpHash.b.size != 0)
170✔
1131
    {
1132
        BOOL OK = FALSE;
13✔
1133
        if(session->attributes.isCpHashDefined)
13✔
1134
            // Compare cpHash.
1135
            OK = MemoryEqual2B(&session->u1.cpHash.b,
8✔
1136
                               &ComputeCpHash(command, session->authHashAlg)->b);
4✔
1137
        else if(g_RuntimeProfile.stateFormatLevel >= 4                // libtpms added
9✔
1138
                && session->attributes.isNameHashDefined)
9✔
1139
            OK = CompareNameHash(command, session);
3✔
1140
        else if(session->attributes.isParametersHashDefined)
6✔
1141
            OK = CompareParametersHash(command, session);
3✔
1142
        else if(session->attributes.isTemplateHashDefined)
3✔
1143
            OK = CompareTemplateHash(command, session);
3✔
UNCOV
1144
        else if (g_RuntimeProfile.stateFormatLevel < 4)                // libtpms added: backwards compatibility
×
UNCOV
1145
            OK = CompareNameHash(command, session);                        // libtpms added: backwards compatibility
×
1146
        if(!OK)
13✔
1147
            return TPM_RCS_POLICY_FAIL;
2✔
1148
    }
1149
    if(session->attributes.checkNvWritten)
168✔
1150
    {
1151
        NV_REF    locator;
4✔
1152
        NV_INDEX* nvIndex;
4✔
1153
        //
1154
        // If this is not an NV index, the policy makes no sense so fail it.
1155
        if(HandleGetType(s_associatedHandles[sessionIndex]) != TPM_HT_NV_INDEX)
4✔
1156
            return TPM_RC_POLICY_FAIL;
1✔
1157
        // Get the index data
1158
        nvIndex = NvGetIndexInfo(s_associatedHandles[sessionIndex], &locator);
4✔
1159

1160
        // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
1161
        if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
4✔
1162
           != (session->attributes.nvWrittenState == SET))
4✔
1163
            return TPM_RC_POLICY_FAIL;
1164
    }
1165
#if SEC_CHANNEL_SUPPORT
1166
    if(session->attributes.checkSecureChannel)
1167
    {
1168
        TPM2B_NAME reqKeyName;
1169
        TPM2B_NAME tpmKeyName;
1170

1171
        // Check that the authorized TPM command is protected by an SPDM session and
1172
        // if so, get the names of the associated requester and TPM key
1173
        if(!IsSpdmSessionActive(&reqKeyName, &tpmKeyName))
1174
            return TPM_RC_CHANNEL;
1175

1176
        // If required, check the requester or TPM secure channel key name by comparing scKeyNameHash
1177
        if(session->attributes.checkReqKey == SET
1178
           || session->attributes.checkTpmKey == SET)
1179
        {
1180
            if(!CompareScKeyNameHash(session, &reqKeyName, &tpmKeyName))
1181
                return TPM_RC_CHANNEL_KEY;
1182
        }
1183
    }
1184
#endif  // SEC_CHANNEL_SUPPORT
1185
    return TPM_RC_SUCCESS;
1186
}
1187

1188
//*** RetrieveSessionData()
1189
// This function will unmarshal the sessions in the session area of a command. The
1190
// values are placed in the arrays that are defined at the beginning of this file.
1191
// The normal unmarshaling errors are possible.
1192
//
1193
//  Return Type: TPM_RC
1194
//      TPM_RC_SUCCSS       unmarshaled without error
1195
//      TPM_RC_SIZE         the number of bytes unmarshaled is not the same
1196
//                          as the value for authorizationSize in the command
1197
//
1198
static TPM_RC RetrieveSessionData(
6,308✔
1199
    COMMAND* command  // IN: main parsing structure for command
1200
)
1201
{
1202
    int          i;
6,308✔
1203
    TPM_RC       result;
6,308✔
1204
    SESSION*     session;
6,308✔
1205
    TPMA_SESSION sessionAttributes;
6,308✔
1206
    TPM_HT       sessionType;
6,308✔
1207
    INT32        sessionIndex;
6,308✔
1208
    TPM_RC       errorIndex;
6,308✔
1209
    //
1210
    s_decryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1211
    s_encryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1212
    s_auditSessionIndex   = UNDEFINED_INDEX;
6,308✔
1213

1214
    for(sessionIndex = 0; command->authSize > 0; sessionIndex++)
13,105✔
1215
    {
1216
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,847✔
1217

1218
        // If maximum allowed number of sessions has been parsed, return a size
1219
        // error with a session number that is larger than the number of allowed
1220
        // sessions
1221
        if(sessionIndex == MAX_SESSION_NUM)
6,847✔
1222
            return TPM_RCS_SIZE + errorIndex;
4✔
1223
        // make sure that the associated handle for each session starts out
1224
        // unassigned
1225
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
6,843✔
1226

1227
        // First parameter: Session handle.
1228
        result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
6,843✔
1229
                                                &command->parameterBuffer,
1230
                                                &command->authSize,
1231
                                                TRUE);
1232
        if(result != TPM_RC_SUCCESS)
6,843✔
1233
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
16✔
1234
        // Second parameter: Nonce.
1235
        result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
6,827✔
1236
                                       &command->parameterBuffer,
1237
                                       &command->authSize);
1238
        if(result != TPM_RC_SUCCESS)
6,827✔
1239
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
8✔
1240
        // Third parameter: sessionAttributes.
1241
        result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
6,819✔
1242
                                        &command->parameterBuffer,
1243
                                        &command->authSize);
1244
        if(result != TPM_RC_SUCCESS)
6,819✔
1245
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
4✔
1246
        // Fourth parameter: authValue (PW or HMAC).
1247
        result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
6,815✔
1248
                                      &command->parameterBuffer,
1249
                                      &command->authSize);
1250
        if(result != TPM_RC_SUCCESS)
6,815✔
1251
            return result + errorIndex;
4✔
1252

1253
        sessionAttributes = s_attributes[sessionIndex];
6,811✔
1254
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,811✔
1255
        {
1256
            // A PWAP session needs additional processing.
1257
            //     Can't have any attributes set other than continueSession bit
1258
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)
5,726✔
1259
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)
1260
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)
5,726✔
1261
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
1262
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset))
5,722✔
1263
                return TPM_RCS_ATTRIBUTES + errorIndex;
4✔
1264
            //     The nonce size must be zero.
1265
            if(s_nonceCaller[sessionIndex].t.size != 0)
5,722✔
1266
                return TPM_RCS_NONCE + errorIndex;
4✔
1267
            continue;
5,718✔
1268
        }
1269
        // For not password sessions...
1270
        // Find out if the session is loaded.
1271
        if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
1,085✔
1272
            return TPM_RC_REFERENCE_S0 + sessionIndex;
6✔
1273
        sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
1,079✔
1274
        session     = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1275
        pAssert_RC(session != NULL);
1,079✔
1276

1277
        // Check if the session is an HMAC/policy session.
1278
        if((session->attributes.isPolicy == SET && sessionType == TPM_HT_HMAC_SESSION)
1,079✔
1279
           || (session->attributes.isPolicy == CLEAR
1,079✔
1280
               && sessionType == TPM_HT_POLICY_SESSION))
871✔
UNCOV
1281
            return TPM_RCS_HANDLE + errorIndex;
×
1282
        // Check that this handle has not previously been used.
1283
        for(i = 0; i < sessionIndex; i++)
1,410✔
1284
        {
1285
            if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
331✔
UNCOV
1286
                return TPM_RCS_HANDLE + errorIndex;
×
1287
        }
1288
        // If the session is used for parameter encryption or audit as well, set
1289
        // the corresponding Indexes.
1290

1291
        // First process decrypt.
1292
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt))
1,079✔
1293
        {
1294
            // Check if the commandCode allows command parameter encryption.
1295
            if(DecryptSize(command->index) == 0)
162✔
UNCOV
1296
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1297
            // Encrypt attribute can only appear in one session
1298
            if(s_decryptSessionIndex != UNDEFINED_INDEX)
162✔
UNCOV
1299
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1300
            // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
1301
            if(session->symmetric.algorithm == TPM_ALG_NULL)
162✔
UNCOV
1302
                return TPM_RCS_SYMMETRIC + errorIndex;
×
1303
            // All checks passed, so set the index for the session used to decrypt
1304
            // a command parameter.
1305
            s_decryptSessionIndex = sessionIndex;
162✔
1306
        }
1307
        // Now process encrypt.
1308
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt))
1,079✔
1309
        {
1310
            // Check if the commandCode allows response parameter encryption.
1311
            if(EncryptSize(command->index) == 0)
154✔
UNCOV
1312
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1313
            // Encrypt attribute can only appear in one session.
1314
            if(s_encryptSessionIndex != UNDEFINED_INDEX)
154✔
UNCOV
1315
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1316
            // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
1317
            if(session->symmetric.algorithm == TPM_ALG_NULL)
154✔
UNCOV
1318
                return TPM_RCS_SYMMETRIC + errorIndex;
×
1319
            // All checks passed, so set the index for the session used to encrypt
1320
            // a response parameter.
1321
            s_encryptSessionIndex = sessionIndex;
154✔
1322
        }
1323
        // At last process audit.
1324
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit))
1,079✔
1325
        {
1326
            // Audit attribute can only appear in one session.
1327
            if(s_auditSessionIndex != UNDEFINED_INDEX)
35✔
UNCOV
1328
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1329
            // An audit session can not be policy session.
1330
            if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION)
35✔
UNCOV
1331
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1332
            // If this is a reset of the audit session, or the first use
1333
            // of the session as an audit session, it doesn't matter what
1334
            // the exclusive state is. The session will become exclusive.
1335
            if(!IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset)
35✔
1336
               && session->attributes.isAudit == SET)
35✔
1337
            {
1338
                // Not first use or reset. If auditExlusive is SET, then this
1339
                // session must be the current exclusive session.
1340
                if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
14✔
UNCOV
1341
                   && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
×
1342
                    return TPM_RC_EXCLUSIVE;
1343
            }
1344
            s_auditSessionIndex = sessionIndex;
35✔
1345
        }
1346
        // Initialize associated handle as undefined. This will be changed when
1347
        // the handles are processed.
1348
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1,079✔
1349
    }
1350
    command->sessionNum = sessionIndex;
6,258✔
1351
    return TPM_RC_SUCCESS;
6,258✔
1352
}
1353

1354
//*** CheckLockedOut()
1355
// This function checks to see if the TPM is in lockout. This function should only
1356
// be called if the entity being checked is subject to DA protection. The TPM
1357
// is in lockout if the NV is not available and a DA write is pending. Otherwise
1358
// the TPM is locked out if checking for lockoutAuth ('lockoutAuthCheck' == TRUE)
1359
// and use of lockoutAuth is disabled, or 'failedTries' >= 'maxTries'
1360
//  Return Type: TPM_RC
1361
//      TPM_RC_NV_RATE          NV is rate limiting
1362
//      TPM_RC_NV_UNAVAILABLE   NV is not available at this time
1363
//      TPM_RC_LOCKOUT          TPM is in lockout
1364
static TPM_RC CheckLockedOut(
158✔
1365
    BOOL lockoutAuthCheck  // IN: TRUE if checking is for lockoutAuth
1366
)
1367
{
1368
    // If NV is unavailable, and current cycle state recorded in NV is not
1369
    // SU_NONE_VALUE, refuse to check any authorization because we would
1370
    // not be able to handle a DA failure.
1371
    if(!NV_IS_AVAILABLE && NV_IS_ORDERLY)
158✔
1372
        return g_NvStatus;
1373
    // Check if DA info needs to be updated in NV.
1374
    if(s_DAPendingOnNV)
158✔
1375
    {
1376
        // If NV is accessible,
UNCOV
1377
        RETURN_IF_NV_IS_NOT_AVAILABLE;
×
1378

1379
        // ... write the pending DA data and proceed.
UNCOV
1380
        NV_SYNC_PERSISTENT(lockOutAuthEnabled);
×
UNCOV
1381
        NV_SYNC_PERSISTENT(failedTries);
×
1382
        s_DAPendingOnNV = FALSE;
×
1383
    }
1384
    // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1385
    // is disabled...
1386
    if(lockoutAuthCheck)
158✔
1387
    {
1388
        if(gp.lockOutAuthEnabled == FALSE)
80✔
UNCOV
1389
            return TPM_RC_LOCKOUT;
×
1390
    }
1391
    else
1392
    {
1393
        // ... or if the number of failed tries has been maxed out.
1394
        if(gp.failedTries >= gp.maxTries)
78✔
1395
            return TPM_RC_LOCKOUT;
1396
#if USE_DA_USED
1397
        // If the daUsed flag is not SET, then no DA validation until the
1398
        // daUsed state is written to NV
1399
        if(!g_daUsed)
40✔
1400
        {
1401
            RETURN_IF_NV_IS_NOT_AVAILABLE;
10✔
1402
            g_daUsed        = TRUE;
10✔
1403
            gp.orderlyState = SU_DA_USED_VALUE;
10✔
1404
            NV_SYNC_PERSISTENT(orderlyState);
10✔
1405
            return TPM_RC_SUCCESS; // libtpms changed: was TPM_RC_RETRY;
10✔
1406
        }
1407
#endif
1408
    }
1409
    return TPM_RC_SUCCESS;
1410
}
1411

1412
//*** CheckAuthSession()
1413
// This function checks that the authorization session properly authorizes the
1414
// use of the associated handle.
1415
//
1416
//  Return Type: TPM_RC
1417
//      TPM_RC_LOCKOUT              entity is protected by DA and TPM is in
1418
//                                  lockout, or TPM is locked out on NV update
1419
//                                  pending on DA parameters
1420
//
1421
//      TPM_RC_PP                   Physical Presence is required but not provided
1422
//      TPM_RC_AUTH_FAIL            HMAC or PW authorization failed
1423
//                                  with DA side-effects (can be a policy session)
1424
//
1425
//      TPM_RC_BAD_AUTH             HMAC or PW authorization failed without DA
1426
//                                  side-effects (can be a policy session)
1427
//
1428
//      TPM_RC_POLICY_FAIL          if policy session fails
1429
//      TPM_RC_POLICY_CC            command code of policy was wrong
1430
//      TPM_RC_EXPIRED              the policy session has expired
1431
//      TPM_RC_PCR
1432
//      TPM_RC_AUTH_UNAVAILABLE     authValue or authPolicy unavailable
1433
static TPM_RC CheckAuthSession(
6,656✔
1434
    COMMAND* command,      // IN: primary parsing structure
1435
    UINT32   sessionIndex  // IN: index of session to be processed
1436
)
1437
{
1438
    TPM_RC     result            = TPM_RC_SUCCESS;
6,656✔
1439
    SESSION*   session           = NULL;
6,656✔
1440
    TPM_HANDLE sessionHandle     = s_sessionHandles[sessionIndex];
6,656✔
1441
    TPM_HANDLE associatedHandle  = s_associatedHandles[sessionIndex];
6,656✔
1442
    TPM_HT     sessionHandleType = HandleGetType(sessionHandle);
6,656✔
1443
    BOOL       authUsed;
6,656✔
1444
    //
1445
    pAssert_RC(sessionHandle != TPM_RH_UNASSIGNED);
6,656✔
1446

1447
    // Take care of physical presence
1448
    if(associatedHandle == TPM_RH_PLATFORM)
6,656✔
1449
    {
1450
        // If the physical presence is required for this command, check for PP
1451
        // assertion. If it isn't asserted, no point going any further.
1452
        if(PhysicalPresenceIsRequired(command->index)
1,023✔
1453
           && !_plat__PhysicalPresenceAsserted())
12✔
1454
            return TPM_RC_PP;
1455
    }
1456
    if(sessionHandle != TPM_RS_PW)
6,644✔
1457
    {
1458
        session = SessionGet(sessionHandle);
980✔
1459
        pAssert_RC(session != NULL);
980✔
1460

1461
        // Set includeAuth to indicate if DA checking will be required and if the
1462
        // authValue will be included in any HMAC.
1463
        if(sessionHandleType == TPM_HT_POLICY_SESSION)
980✔
1464
        {
1465
            // For a policy session, will check the DA status of the entity if either
1466
            // isAuthValueNeeded or isPasswordNeeded is SET.
1467
            session->attributes.includeAuth = session->attributes.isAuthValueNeeded
208✔
1468
                                              || session->attributes.isPasswordNeeded;
208✔
1469
        }
1470
        else
1471
        {
1472
            // For an HMAC session, need to check unless the session
1473
            // is bound.
1474
            session->attributes.includeAuth =
1,544✔
1475
                !IsSessionBindEntity(s_associatedHandles[sessionIndex], session);
772✔
1476
        }
1477
        authUsed = session->attributes.includeAuth;
980✔
1478
    }
1479
    else
1480
        // Password session
1481
        authUsed = TRUE;
1482
    // If the authorization session is going to use an authValue, then make sure
1483
    // that access to that authValue isn't locked out.
1484
    if(authUsed)
980✔
1485
    {
1486
        // See if entity is subject to lockout.
1487
        if(!IsDAExempted(associatedHandle))
6,409✔
1488
        {
1489
            // See if in lockout
1490
            result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
158✔
1491
            if(result != TPM_RC_SUCCESS)
158✔
1492
                return result;
1493
        }
1494
    }
1495
    // Policy or HMAC+PW?
1496
    if(sessionHandleType != TPM_HT_POLICY_SESSION)
6,606✔
1497
    {
1498
        // for non-policy session make sure that a policy session is not required
1499
        if(IsPolicySessionRequired(command->index, sessionIndex))
6,398✔
1500
            return TPM_RC_AUTH_TYPE;
1501
        // The authValue must be available.
1502
        // Note: The authValue is going to be "used" even if it is an EmptyAuth.
1503
        // and the session is bound.
1504
        if(!IsAuthValueAvailable(associatedHandle, command->index, sessionIndex))
6,396✔
1505
            return TPM_RC_AUTH_UNAVAILABLE;
1506
    }
1507
    else
1508
    {
1509
        // ... see if the entity has a policy, ...
1510
        // Note: IsAuthPolicyAvalable will return FALSE if the sensitive area of the
1511
        // object is not loaded
1512
        if(!IsAuthPolicyAvailable(associatedHandle, command->index, sessionIndex))
208✔
1513
            return TPM_RC_AUTH_UNAVAILABLE;
1514
        // ... and check the policy session.
1515
        result = CheckPolicyAuthSession(command, sessionIndex);
208✔
1516
        if(result != TPM_RC_SUCCESS)
208✔
1517
            return result;
1518
    }
1519
    // Check authorization according to the type
1520
    if((TPM_RS_PW == sessionHandle) || (session->attributes.isPasswordNeeded == SET))
6,536✔
1521
        result = CheckPWAuthSession(sessionIndex);
5,607✔
1522
    else
1523
        result = CheckSessionHMAC(command, sessionIndex);
929✔
1524
    // Do processing for PIN Indexes are only three possibilities for 'result' at
1525
    // this point: TPM_RC_SUCCESS, TPM_RC_AUTH_FAIL, and TPM_RC_BAD_AUTH.
1526
    // For all these cases, we would have to process a PIN index if the
1527
    // authValue of the index was used for authorization.
1528
    if((TPM_HT_NV_INDEX == HandleGetType(associatedHandle)) && authUsed)
6,536✔
1529
    {
1530
        NV_REF    locator;
488✔
1531
        NV_INDEX* nvIndex = NULL;
488✔
1532
        NV_PIN    pinData;
488✔
1533
        TPMA_NV   nvAttributes;
488✔
1534
        NV_INDEX  tempIndex = {0};
488✔
1535

1536
        if(_plat__IsNvVirtualIndex(associatedHandle))
488✔
1537
        {
NEW
1538
            _plat__NvVirtual_PopulateNvIndexInfo(
×
1539
                associatedHandle, &tempIndex.publicArea, &tempIndex.authValue);
NEW
1540
            nvIndex = &tempIndex;
×
1541

NEW
1542
            locator = (NV_REF)0;
×
1543
        }
1544
        else
1545
        {
1546
            nvIndex = NvGetIndexInfo(associatedHandle, &locator);
488✔
1547
        }
1548

1549
        //
1550
        pAssert_RC(nvIndex != NULL);
488✔
1551
        nvAttributes = nvIndex->publicArea.attributes;
488✔
1552
        // If this is a PIN FAIL index and the value has been written
1553
        // then we can update the counter (increment or clear)
1554
        if(IsNvPinFailIndex(nvAttributes)
488✔
1555
           && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
13✔
1556
        {
1557
            if(locator == (NV_REF)0)
13✔
NEW
1558
                return TPM_RC_AUTH_UNAVAILABLE;
×
1559
            pinData.intVal = NvGetUINT64Data(nvIndex, locator);
13✔
1560
            if(result != TPM_RC_SUCCESS)
13✔
1561
                pinData.pin.pinCount++;
6✔
1562
            else
1563
                pinData.pin.pinCount = 0;
7✔
1564
            NvWriteUINT64Data(nvIndex, pinData.intVal);
13✔
1565
        }
1566
        // If this is a PIN PASS Index, increment if we have used the
1567
        // authorization value.
1568
        // NOTE: If the counter has already hit the limit, then we
1569
        // would not get here because the authorization value would not
1570
        // be available and the TPM would have returned before it gets here
1571
        else if(IsNvPinPassIndex(nvAttributes)
475✔
1572
                && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN)
8✔
1573
                && result == TPM_RC_SUCCESS)
8✔
1574
        {
1575
            if(locator == (NV_REF)0)
7✔
1576
                return TPM_RC_AUTH_UNAVAILABLE;
1577
            // If the access is valid, then increment the use counter
1578
            pinData.intVal = NvGetUINT64Data(nvIndex, locator);
7✔
1579
            pinData.pin.pinCount++;
7✔
1580
            NvWriteUINT64Data(nvIndex, pinData.intVal);
7✔
1581
        }
1582
    }
1583
    return result;
1584
}
1585

1586
#if CC_GetCommandAuditDigest
1587
//*** CheckCommandAudit()
1588
// This function is called before the command is processed if audit is enabled
1589
// for the command. It will check to see if the audit can be performed and
1590
// will ensure that the cpHash is available for the audit.
1591
//  Return Type: TPM_RC
1592
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
1593
//      TPM_RC_NV_RATE              NV is rate limiting
1594
static TPM_RC CheckCommandAudit(COMMAND* command)
65✔
1595
{
1596
    // If the audit digest is clear and command audit is required, NV must be
1597
    // available so that TPM2_GetCommandAuditDigest() is able to increment
1598
    // audit counter. If NV is not available, the function bails out to prevent
1599
    // the TPM from attempting an operation that would fail anyway.
1600
    if(gr.commandAuditDigest.t.size == 0
65✔
UNCOV
1601
       || GetCommandCode(command->index) == TPM_CC_GetCommandAuditDigest)
×
1602
    {
1603
        RETURN_IF_NV_IS_NOT_AVAILABLE;
65✔
1604
    }
1605
    // Make sure that the cpHash is computed for the algorithm
1606
    ComputeCpHash(command, gp.auditHashAlg);
65✔
1607
    return TPM_RC_SUCCESS;
65✔
1608
}
1609
#endif
1610

1611
//*** ParseSessionBuffer()
1612
// This function is the entry function for command session processing.
1613
// It iterates sessions in session area and reports if the required authorization
1614
// has been properly provided. It also processes audit session and passes the
1615
// information of encryption sessions to parameter encryption module.
1616
//
1617
//  Return Type: TPM_RC
1618
//        various           parsing failure or authorization failure
1619
//
1620
TPM_RC
1621
ParseSessionBuffer(COMMAND* command  // IN: the structure that contains
6,308✔
1622
)
1623
{
1624
    TPM_RC     result;
6,308✔
1625
    UINT32     i;
6,308✔
1626
    INT32      size = 0;
6,308✔
1627
    TPM2B_AUTH extraKey;
6,308✔
1628
    UINT32     sessionIndex;
6,308✔
1629
    TPM_RC     errorIndex;
6,308✔
1630
    SESSION*   session = NULL;
6,308✔
1631
    //
1632
    // Check if a command allows any session in its session area.
1633
    if(!IsSessionAllowed(command->index))
6,308✔
1634
        return TPM_RC_AUTH_CONTEXT;
1635
    // Default-initialization.
1636
    command->sessionNum = 0;
6,308✔
1637

1638
    result              = RetrieveSessionData(command);
6,308✔
1639
    if(result != TPM_RC_SUCCESS)
6,308✔
1640
        return result;
1641
    // There is no command in the TPM spec that has more handles than
1642
    // MAX_SESSION_NUM.
1643
    pAssert_RC(command->handleNum <= MAX_SESSION_NUM);
6,258✔
1644

1645
    // Associate the session with an authorization handle.
1646
    for(i = 0; i < command->handleNum; i++)
14,773✔
1647
    {
1648
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
8,515✔
1649
        {
1650
            // If the received session number is less than the number of handles
1651
            // that requires authorization, an error should be returned.
1652
            // Note: for all the TPM 2.0 commands, handles requiring
1653
            // authorization come first in a command input and there are only ever
1654
            // two values requiring authorization
1655
            if(command->sessionNum == 0)                // libtpms added begin (Coverity 1550499)
6,662✔
1656
                return TPM_RC_AUTH_MISSING;                // libtpms added end
1657
            if(i > (command->sessionNum - 1))
6,662✔
1658
                return TPM_RC_AUTH_MISSING;
1659
            // Record the handle associated with the authorization session
1660
            s_associatedHandles[i] = HierarchyNormalizeHandle(command->handles[i]);
6,662✔
1661
        }
1662
    }
1663
    // Consistency checks are done first to avoid authorization failure when the
1664
    // command will not be executed anyway.
1665
    for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++)
12,804✔
1666
    {
1667
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,767✔
1668
        // PW session must be an authorization session
1669
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,767✔
1670
        {
1671
            if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
5,688✔
1672
                return TPM_RCS_HANDLE + errorIndex;
12✔
1673
            // a password session can't be audit, encrypt or decrypt
1674
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
5,676✔
1675
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1676
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
5,676✔
UNCOV
1677
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1678
            session = NULL;
1679
        }
1680
        else
1681
        {
1682
            session = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1683
            pAssert_RC(session != NULL);
1,079✔
1684

1685
            // A trial session can not appear in session area, because it cannot
1686
            // be used for authorization, audit or encrypt/decrypt.
1687
            if(session->attributes.isTrialPolicy == SET)
1,079✔
UNCOV
1688
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1689

1690
            // See if the session is bound to a DA protected entity
1691
            // NOTE: Since a policy session is never bound, a policy is still
1692
            // usable even if the object is DA protected and the TPM is in
1693
            // lockout.
1694
            if(session->attributes.isDaBound == SET)
1,079✔
1695
            {
UNCOV
1696
                result = CheckLockedOut(session->attributes.isLockoutBound == SET);
×
UNCOV
1697
                if(result != TPM_RC_SUCCESS)
×
UNCOV
1698
                    return result;
×
1699
            }
1700
            // If this session is for auditing, make sure the cpHash is computed.
1701
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit))
1,079✔
1702
                ComputeCpHash(command, session->authHashAlg);
35✔
1703
        }
1704

1705
        // if the session has an associated handle, check the authorization
1706
        if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
6,755✔
1707
        {
1708
            result = CheckAuthSession(command, sessionIndex);
6,656✔
1709
            if(result != TPM_RC_SUCCESS)
6,656✔
1710
                return RcSafeAddToResult(result, errorIndex);
209✔
1711
        }
1712
        else
1713
        {
1714
            // a session that is not for authorization must either be encrypt,
1715
            // decrypt, or audit
1716
            if(!IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
99✔
1717
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1718
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
88✔
UNCOV
1719
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1720

1721
            // no authValue included in any of the HMAC computations
1722
            pAssert_RC(session != NULL);
99✔
1723
            session->attributes.includeAuth = CLEAR;
99✔
1724

1725
            // check HMAC for encrypt/decrypt/audit only sessions
1726
            result = CheckSessionHMAC(command, sessionIndex);
99✔
1727
            if(result != TPM_RC_SUCCESS)
99✔
UNCOV
1728
                return RcSafeAddToResult(result, errorIndex);
×
1729
        }
1730
    }
1731
#if CC_GetCommandAuditDigest
1732
    // Check if the command should be audited. Need to do this before any parameter
1733
    // encryption so that the cpHash for the audit is correct
1734
    if(CommandAuditIsRequired(command->index))
6,037✔
1735
    {
1736
        result = CheckCommandAudit(command);
65✔
1737
        if(result != TPM_RC_SUCCESS)
65✔
1738
            return result;  // No session number to reference
1739
    }
1740
#endif
1741
    // Decrypt the first parameter if applicable. This should be the last operation
1742
    // in session processing.
1743
    // If the encrypt session is associated with a handle and the handle's
1744
    // authValue is available, then authValue is concatenated with sessionKey to
1745
    // generate encryption key, no matter if the handle is the session bound entity
1746
    // or not.
1747
    if(s_decryptSessionIndex != UNDEFINED_INDEX)
6,037✔
1748
    {
1749
        // If this is an authorization session, include the authValue in the
1750
        // generation of the decryption key
1751
        if(s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED)
160✔
1752
        {
1753
            EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], &extraKey);
110✔
1754
        }
1755
        else
1756
        {
1757
            extraKey.b.size = 0;
50✔
1758
        }
1759
        size = DecryptSize(command->index);
160✔
1760
        pAssert_RC(command->parameterSize <= INT32_MAX);
160✔
1761
        result = CryptParameterDecryption(s_sessionHandles[s_decryptSessionIndex],
320✔
1762
                                          &s_nonceCaller[s_decryptSessionIndex].b,
160✔
1763
                                          command->parameterSize,
1764
                                          (UINT16)size,
1765
                                          &extraKey,
1766
                                          command->parameterBuffer);
1767
        if(result != TPM_RC_SUCCESS)
160✔
1768
            return RcSafeAddToResult(result,
2✔
1769
                                     TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
2✔
1770
    }
1771

1772
    return TPM_RC_SUCCESS;
1773
}
1774

1775
//*** CheckAuthNoSession()
1776
// Function to process a command with no session associated.
1777
// The function makes sure all the handles in the command require no authorization.
1778
//
1779
//  Return Type: TPM_RC
1780
//      TPM_RC_AUTH_MISSING         failure - one or more handles require
1781
//                                  authorization
1782
TPM_RC
1783
CheckAuthNoSession(COMMAND* command  // IN: command parsing structure
10,515✔
1784
)
1785
{
1786
    UINT32 i;
10,515✔
1787
#if CC_GetCommandAuditDigest
1788
    TPM_RC result = TPM_RC_SUCCESS;
10,515✔
1789
#endif
1790
    //
1791
    // Check if the command requires authorization
1792
    for(i = 0; i < command->handleNum; i++)
13,058✔
1793
    {
1794
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
2,567✔
1795
            return TPM_RC_AUTH_MISSING;
1796
    }
1797
#if CC_GetCommandAuditDigest
1798
    // Check if the command should be audited.
1799
    if(CommandAuditIsRequired(command->index))
10,491✔
1800
    {
UNCOV
1801
        result = CheckCommandAudit(command);
×
UNCOV
1802
        if(result != TPM_RC_SUCCESS)
×
1803
            return result;
1804
    }
1805
#endif
1806
    // Initialize number of sessions to be 0
1807
    command->sessionNum = 0;
10,491✔
1808

1809
    return TPM_RC_SUCCESS;
10,491✔
1810
}
1811

1812
//** Response Session Processing
1813
//*** Introduction
1814
//
1815
//  The following functions build the session area in a response and handle
1816
//  the audit sessions (if present).
1817
//
1818

1819
//*** ComputeRpHash()
1820
// Function to compute rpHash (Response Parameter Hash). The rpHash is only
1821
// computed if there is an HMAC authorization session and the return code is
1822
// TPM_RC_SUCCESS.
1823
static TPM2B_DIGEST* ComputeRpHash(
1,026✔
1824
    COMMAND*   command,  // IN: command structure
1825
    TPM_ALG_ID hashAlg   // IN: hash algorithm to compute rpHash
1826
)
1827
{
1828
    TPM2B_DIGEST* rpHash = GetRpHashPointer(command, hashAlg);
1,026✔
1829
    HASH_STATE    hashState;
1,026✔
1830
    //
1831
    if(rpHash->t.size == 0)
1,026✔
1832
    {
1833
        //   rpHash := hash(responseCode || commandCode || parameters)
1834

1835
        // Initiate hash creation.
1836
        rpHash->t.size = CryptHashStart(&hashState, hashAlg);
749✔
1837

1838
        // Add hash constituents.
1839
        CryptDigestUpdateInt(&hashState, sizeof(TPM_RC), TPM_RC_SUCCESS);
749✔
1840
        CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
749✔
1841
        CryptDigestUpdate(
749✔
1842
            &hashState, command->parameterSize, command->parameterBuffer);
749✔
1843
        // Complete hash computation.
1844
        CryptHashEnd2B(&hashState, &rpHash->b);
749✔
1845
    }
1846
    return rpHash;
1,026✔
1847
}
1848

1849
//*** InitAuditSession()
1850
// This function initializes the audit data in an audit session.
1851
static void InitAuditSession(SESSION* session  // session to be initialized
21✔
1852
)
1853
{
1854
    // Mark session as an audit session.
1855
    session->attributes.isAudit = SET;
21✔
1856

1857
    // Audit session can not be bound.
1858
    session->attributes.isBound = CLEAR;
21✔
1859

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

1863
    // Set the original digest value to be 0.
1864
    MemorySet(&session->u2.auditDigest.t.buffer, 0, session->u2.auditDigest.t.size);
21✔
1865
    return;
21✔
1866
}
1867

1868
//*** UpdateAuditDigest
1869
// Function to update an audit digest
1870
static void UpdateAuditDigest(
52✔
1871
    COMMAND* command, TPMI_ALG_HASH hashAlg, TPM2B_DIGEST* digest)
1872
{
1873
    HASH_STATE    hashState;
52✔
1874
    TPM2B_DIGEST* cpHash = GetCpHash(command, hashAlg);
52✔
1875
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, hashAlg);
52✔
1876
    //
1877
    pAssert_VOID_OK(cpHash != NULL);
52✔
1878

1879
    // digestNew :=  hash (digestOld || cpHash || rpHash)
1880
    // Start hash computation.
1881
    digest->t.size = CryptHashStart(&hashState, hashAlg);
52✔
1882
    // Add old digest.
1883
    CryptDigestUpdate2B(&hashState, &digest->b);
52✔
1884
    // Add cpHash
1885
    CryptDigestUpdate2B(&hashState, &cpHash->b);
52✔
1886
    // Add rpHash
1887
    CryptDigestUpdate2B(&hashState, &rpHash->b);
52✔
1888
    // Finalize the hash.
1889
    CryptHashEnd2B(&hashState, &digest->b);
52✔
1890
}
52✔
1891

1892
//*** Audit()
1893
//This function updates the audit digest in an audit session.
1894
static void Audit(COMMAND* command,      // IN: primary control structure
35✔
1895
                  SESSION* auditSession  // IN: loaded audit session
1896
)
1897
{
1898
    UpdateAuditDigest(
35✔
1899
        command, auditSession->authHashAlg, &auditSession->u2.auditDigest);
35✔
1900
    return;
35✔
1901
}
1902

1903
#if CC_GetCommandAuditDigest
1904
//*** CommandAudit()
1905
// This function updates the command audit digest.
1906
static void CommandAudit(COMMAND* command  // IN:
17✔
1907
)
1908
{
1909
    // If the digest.size is one, it indicates the special case of changing
1910
    // the audit hash algorithm. For this case, no audit is done on exit.
1911
    // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1912
    // force an update to the NV on exit so that the change in digest will
1913
    // be recorded. So, it is safe to exit here without setting any flags
1914
    // because the digest change will be written to NV when this code exits.
1915
    if(gr.commandAuditDigest.t.size == 1)
17✔
1916
    {
UNCOV
1917
        gr.commandAuditDigest.t.size = 0;
×
UNCOV
1918
        return;
×
1919
    }
1920
    // If the digest size is zero, need to start a new digest and increment
1921
    // the audit counter.
1922
    if(gr.commandAuditDigest.t.size == 0)
17✔
1923
    {
1924
        gr.commandAuditDigest.t.size = CryptHashGetDigestSize(gp.auditHashAlg);
17✔
1925
        MemorySet(gr.commandAuditDigest.t.buffer, 0, gr.commandAuditDigest.t.size);
17✔
1926

1927
        // Bump the counter and save its value to NV.
1928
        gp.auditCounter++;
17✔
1929
        NV_SYNC_PERSISTENT(auditCounter);
17✔
1930
    }
1931
    UpdateAuditDigest(command, gp.auditHashAlg, &gr.commandAuditDigest);
17✔
1932
    return;
17✔
1933
}
1934
#endif
1935

1936
//*** UpdateAuditSessionStatus()
1937
// This function updates the internal audit related states of a session. It will:
1938
//  a) initialize the session as audit session and set it to be exclusive if this
1939
//     is the first time it is used for audit or audit reset was requested;
1940
//  b) report exclusive audit session;
1941
//  c) extend audit log; and
1942
//  d) clear exclusive audit session if no audit session found in the command.
1943
static void UpdateAuditSessionStatus(
14,596✔
1944
    COMMAND* command  // IN: primary control structure
1945
)
1946
{
1947
    UINT32     i;
14,596✔
1948
    TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
14,596✔
1949
    //
1950
    // Iterate through sessions
1951
    for(i = 0; i < command->sessionNum; i++)
20,280✔
1952
    {
1953
        SESSION* session;
5,684✔
1954
        //
1955
        // PW session do not have a loaded session and can not be an audit
1956
        // session either.  Skip it.
1957
        if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
1958
            continue;
4,706✔
1959
        session = SessionGet(s_sessionHandles[i]);
978✔
1960
        pAssert_VOID_OK(session != NULL);
978✔
1961

1962
        // If a session is used for audit
1963
        if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit))
978✔
1964
        {
1965
            // An audit session has been found
1966
            auditSession = s_sessionHandles[i];
35✔
1967

1968
            // If the session has not been an audit session yet, or
1969
            // the auditSetting bits indicate a reset, initialize it and set
1970
            // it to be the exclusive session
1971
            if(session->attributes.isAudit == CLEAR
35✔
1972
               || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset))
14✔
1973
            {
1974
                InitAuditSession(session);
21✔
1975
                g_exclusiveAuditSession = auditSession;
21✔
1976
            }
1977
            else
1978
            {
1979
                // Check if the audit session is the current exclusive audit
1980
                // session and, if not, clear previous exclusive audit session.
1981
                if(g_exclusiveAuditSession != auditSession)
14✔
1982
                    g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
5✔
1983
            }
1984
            // Report audit session exclusivity.
1985
            if(g_exclusiveAuditSession == auditSession)
35✔
1986
            {
1987
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
30✔
1988
            }
1989
            else
1990
            {
1991
                CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
5✔
1992
            }
1993
            // Extend audit log.
1994
            Audit(command, session);
5,719✔
1995
        }
1996
    }
1997
    // If no audit session is found in the command, and the command allows
1998
    // a session then, clear the current exclusive
1999
    // audit session.
2000
    if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index))
14,596✔
2001
    {
2002
        g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
9,283✔
2003
    }
2004
    return;
14,596✔
2005
}
2006

2007
//*** ComputeResponseHMAC()
2008
// Function to compute HMAC for authorization session in a response.
2009
/*(See part 1 specification)
2010
// Function: Compute HMAC for response sessions
2011
//      The sessionAuth value
2012
//          authHMAC := HMACsHASH((sessionAuth | authValue),
2013
//                    (pHash | nonceTPM | nonceCaller | sessionAttributes))
2014
//  Where:
2015
//      HMACsHASH()     The HMAC algorithm using the hash algorithm specified when
2016
//                      the session was started.
2017
//
2018
//      sessionAuth     A TPMB_MEDIUM computed in a protocol-dependent way, using
2019
//                      KDFa. In an HMAC or KDF, only sessionAuth.buffer is used.
2020
//
2021
//      authValue       A TPM2B_AUTH that is found in the sensitive area of an
2022
//                      object. In an HMAC or KDF, only authValue.buffer is used
2023
//                      and all trailing zeros are removed.
2024
//
2025
//      pHash           Response parameters (rpHash) using the session hash. When
2026
//                      using a pHash in an HMAC computation, both the algorithm ID
2027
//                      and the digest are included.
2028
//
2029
//      nonceTPM        A TPM2B_NONCE that is generated by the entity using the
2030
//                      session. In an HMAC or KDF, only nonceTPM.buffer is used.
2031
//
2032
//      nonceCaller     a TPM2B_NONCE that was received the previous time the
2033
//                      session was used. In an HMAC or KDF, only
2034
//                      nonceCaller.buffer is used.
2035
//
2036
//      sessionAttributes   A TPMA_SESSION that indicates the attributes associated
2037
//                          with a particular use of the session.
2038
*/
2039
static void ComputeResponseHMAC(
974✔
2040
    COMMAND*      command,       // IN: command structure
2041
    UINT32        sessionIndex,  // IN: session index to be processed
2042
    SESSION*      session,       // IN: loaded session
2043
    TPM2B_DIGEST* hmac           // OUT: authHMAC
2044
)
2045
{
2046
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
974✔
2047
    TPM2B_KEY     key;  // HMAC key
974✔
2048
    BYTE          marshalBuffer[sizeof(TPMA_SESSION)];
974✔
2049
    BYTE*         buffer;
974✔
2050
    UINT32        marshalSize;
974✔
2051
    HMAC_STATE    hmacState;
974✔
2052
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, session->authHashAlg);
974✔
2053
    //
2054
    // Generate HMAC key
2055
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
974✔
2056

2057
    // Add the object authValue if required
2058
    if(session->attributes.includeAuth == SET)
974✔
2059
    {
2060
        // Note: includeAuth may be SET for a policy that is used in
2061
        // UndefineSpaceSpecial(). At this point, the Index has been deleted
2062
        // so the includeAuth will have no meaning. However, the
2063
        // s_associatedHandles[] value for the session is now set to TPM_RH_NULL so
2064
        // this will return the authValue associated with TPM_RH_NULL and that is
2065
        // and empty buffer.
2066
        TPM2B_AUTH authValue;
682✔
2067
        //
2068
        // Get the authValue with trailing zeros removed
2069
        EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
682✔
2070

2071
        // Add it to the key
2072
        MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
682✔
2073
    }
2074

2075
    // if the HMAC key size is 0, the response HMAC is computed according to the
2076
    // input HMAC
2077
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
974✔
2078
    {
2079
        hmac->t.size = 0;
127✔
2080
        return;
127✔
2081
    }
2082
    // Start HMAC computation.
2083
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
847✔
2084

2085
    // Add hash components.
2086
    CryptDigestUpdate2B(&hmacState.hashState, &rpHash->b);
847✔
2087
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
847✔
2088
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
847✔
2089

2090
    // Add session attributes.
2091
    buffer      = marshalBuffer;
847✔
2092
    marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL);
847✔
2093
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
847✔
2094

2095
    // Finalize HMAC.
2096
    CryptHmacEnd2B(&hmacState, &hmac->b);
847✔
2097

2098
    return;
847✔
2099
}
2100

2101
//*** UpdateInternalSession()
2102
// This function updates internal sessions by:
2103
// a) restarting session time; and
2104
// b) clearing a policy session since nonce is rolling.
2105
static void UpdateInternalSession(SESSION* session,  // IN: the session structure
978✔
2106
                                  UINT32   i         // IN: session number
2107
)
2108
{
2109
    // If nonce is rolling in a policy session, the policy related data
2110
    // will be re-initialized.
2111
    if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION
978✔
2112
       && IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
165✔
2113
    {
2114
        // When the nonce rolls it starts a new timing interval for the
2115
        // policy session.
2116
        SessionResetPolicyData(session);
121✔
2117
        SessionSetStartTime(session);
121✔
2118
    }
2119
    return;
978✔
2120
}
2121

2122
//*** BuildSingleResponseAuth()
2123
//   Function to compute response HMAC value for a policy or HMAC session.
2124
static TPM2B_NONCE* BuildSingleResponseAuth(
978✔
2125
    COMMAND*    command,       // IN: command structure
2126
    UINT32      sessionIndex,  // IN: session index to be processed
2127
    TPM2B_AUTH* auth           // OUT: authHMAC
2128
)
2129
{
2130
    // Fill in policy/HMAC based session response.
2131
    SESSION* session = SessionGet(s_sessionHandles[sessionIndex]);
978✔
2132
    pAssert_NULL(session != NULL);
978✔
2133

2134
    // If the session is a policy session with isPasswordNeeded SET, the
2135
    // authorization field is empty.
2136
    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
978✔
2137
       && session->attributes.isPasswordNeeded == SET)
165✔
2138
        auth->t.size = 0;
4✔
2139
    else
2140
        // Compute response HMAC.
2141
        ComputeResponseHMAC(command, sessionIndex, session, auth);
974✔
2142

2143
    UpdateInternalSession(session, sessionIndex);
978✔
2144
    return &session->nonceTPM;
978✔
2145
}
2146

2147
//*** UpdateAllNonceTPM()
2148
// Updates TPM nonce for all sessions in command.
2149
static void UpdateAllNonceTPM(COMMAND* command  // IN: controlling structure
5,210✔
2150
)
2151
{
2152
    UINT32   i;
5,210✔
2153
    SESSION* session;
5,210✔
2154
    //
2155
    for(i = 0; i < command->sessionNum; i++)
10,894✔
2156
    {
2157
        // If not a PW session, compute the new nonceTPM.
2158
        if(s_sessionHandles[i] != TPM_RS_PW)
5,684✔
2159
        {
2160
            session = SessionGet(s_sessionHandles[i]);
978✔
2161
            pAssert_VOID_OK(session != NULL);
978✔
2162
            // Update nonceTPM in both internal session and response.
2163
            CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
978✔
2164
        }
2165
    }
2166
    return;
5,210✔
2167
}
2168

2169
//*** BuildResponseSession()
2170
// Function to build Session buffer in a response. The authorization data is added
2171
// to the end of command->responseBuffer. The size of the authorization area is
2172
// accumulated in command->authSize.
2173
// When this is called, command->responseBuffer is pointing at the next location
2174
// in the response buffer to be filled. This is where the authorization sessions
2175
// will go, if any. command->parameterSize is the number of bytes that have been
2176
// marshaled as parameters in the output buffer.
2177
TPM_RC
2178
BuildResponseSession(COMMAND* command  // IN: structure that has relevant command
14,596✔
2179
                                       //     information
2180
)
2181
{
2182
    TPM_RC result = TPM_RC_SUCCESS;
14,596✔
2183

2184
    pAssert_RC(command->authSize == 0);
14,596✔
2185

2186
    // Reset the parameter buffer to point to the start of the parameters so that
2187
    // there is a starting point for any rpHash that might be generated and so there
2188
    // is a place where parameter encryption would start
2189
    command->parameterBuffer = command->responseBuffer - command->parameterSize;
14,596✔
2190

2191
    // Session nonces should be updated before parameter encryption
2192
    if(command->tag == TPM_ST_SESSIONS)
14,596✔
2193
    {
2194
        UpdateAllNonceTPM(command);
5,210✔
2195
        VERIFY_NOT_FAILED();
5,210✔
2196

2197
        // Encrypt first parameter if applicable. Parameter encryption should
2198
        // happen after nonce update and before any rpHash is computed.
2199
        // If the encrypt session is associated with a handle, the authValue of
2200
        // this handle will be concatenated with sessionKey to generate
2201
        // encryption key, no matter if the handle is the session bound entity
2202
        // or not. The authValue is added to sessionKey only when the authValue
2203
        // is available.
2204
        if(s_encryptSessionIndex != UNDEFINED_INDEX)
5,210✔
2205
        {
2206
            UINT32     size;
152✔
2207
            TPM2B_AUTH extraKey;
152✔
2208
            //
2209
            extraKey.b.size = 0;
152✔
2210
            // If this is an authorization session, include the authValue in the
2211
            // generation of the encryption key
2212
            if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED)
152✔
2213
            {
2214
                EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
102✔
2215
                                   &extraKey);
2216
            }
2217
            size = EncryptSize(command->index);
152✔
2218
            pAssert_RC(command->parameterSize <= INT32_MAX);
152✔
2219
            // This function operates on internally-generated data that is
2220
            // expected to be well-formed for parameter encryption.
2221
            // In the event that there is a bug elsewhere in the code and the
2222
            // input data is not well-formed, CryptParameterEncryption will
2223
            // put the TPM into failure mode instead of allowing the out-of-
2224
            // band write.
2225
            CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
152✔
2226
                                     &s_nonceCaller[s_encryptSessionIndex].b,
152✔
2227
                                     command->parameterSize,
2228
                                     (UINT16)size,
2229
                                     &extraKey,
2230
                                     command->parameterBuffer);
2231
            if(_plat__InFailureMode())
152✔
2232
            {
UNCOV
2233
                result = TPM_RC_FAILURE;
×
UNCOV
2234
                goto Cleanup;
×
2235
            }
2236
        }
2237
    }
2238
    // Audit sessions should be processed regardless of the tag because
2239
    // a command with no session may cause a change of the exclusivity state.
2240
    UpdateAuditSessionStatus(command);
14,596✔
2241
    VERIFY_NOT_FAILED();
14,596✔
2242
#if CC_GetCommandAuditDigest
2243
    // Command Audit
2244
    if(CommandAuditIsRequired(command->index))
14,596✔
2245
        CommandAudit(command);
17✔
2246
#endif
2247
    // Process command with sessions.
2248
    if(command->tag == TPM_ST_SESSIONS)
14,596✔
2249
    {
2250
        UINT32 i;
5,210✔
2251
        //
2252
        pAssert_RC(command->sessionNum > 0);
5,210✔
2253

2254
        // Iterate over each session in the command session area, and create
2255
        // corresponding sessions for response.
2256
        for(i = 0; i < command->sessionNum; i++)
10,894✔
2257
        {
2258
            TPM2B_NONCE* nonceTPM;
5,684✔
2259
            TPM2B_DIGEST responseAuth;
5,684✔
2260
            // Make sure that continueSession is SET on any Password session.
2261
            // This makes it marginally easier for the management software
2262
            // to keep track of the closed sessions.
2263
            if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
2264
            {
2265
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession);
4,706✔
2266
                responseAuth.t.size = 0;
4,706✔
2267
                nonceTPM            = (TPM2B_NONCE*)&responseAuth;
4,706✔
2268
            }
2269
            else
2270
            {
2271
                // Compute the response HMAC and get a pointer to the nonce used.
2272
                // This function will also update the values if needed. Note, the
2273
                nonceTPM = BuildSingleResponseAuth(command, i, &responseAuth);
978✔
2274
                pAssert_RC(nonceTPM != NULL);
978✔
2275
            }
2276
            command->authSize +=
11,368✔
2277
                TPM2B_NONCE_Marshal(nonceTPM, &command->responseBuffer, NULL);
5,684✔
2278
            command->authSize += TPMA_SESSION_Marshal(
5,684✔
2279
                &s_attributes[i], &command->responseBuffer, NULL);
2280
            command->authSize +=
11,368✔
2281
                TPM2B_DIGEST_Marshal(&responseAuth, &command->responseBuffer, NULL);
5,684✔
2282
            if(!IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
5,684✔
2283
            {
2284
                SessionFlush(s_sessionHandles[i]);
89✔
2285
                VERIFY_NOT_FAILED();
5,684✔
2286
            }
2287
        }
2288
    }
2289

2290
Cleanup:
14,596✔
2291
    return result;
2292
}
2293

2294
//*** SessionRemoveAssociationToHandle()
2295
// This function deals with the case where an entity associated with an authorization
2296
// is deleted during command processing. The primary use of this is to support
2297
// UndefineSpaceSpecial().
2298
void SessionRemoveAssociationToHandle(TPM_HANDLE handle)
2✔
2299
{
2300
    UINT32 i;
2✔
2301
    //
2302
    for(i = 0; i < MAX_SESSION_NUM; i++)
8✔
2303
    {
2304
        if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle))
6✔
2305
        {
2306
            s_associatedHandles[i] = TPM_RH_NULL;
2✔
2307
        }
2308
    }
2309
}
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