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

stefanberger / libtpms / #2033

04 Dec 2025 02:24PM UTC coverage: 77.218% (-0.003%) from 77.221%
#2033

push

travis-ci

web-flow
Merge 914712db4 into 4f71e9b45

50 of 63 new or added lines in 13 files covered. (79.37%)

897 existing lines in 26 files now uncovered.

36122 of 46779 relevant lines covered (77.22%)

125357.09 hits per line

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

91.37
/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
#if SEC_CHANNEL_SUPPORT
17
#  include "SecChannel_fp.h"
18
#endif  // SEC_CHANNEL_SUPPORT
19

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

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

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

112
        // lockout is no longer enabled
113
        gp.lockOutAuthEnabled = FALSE;
4✔
114

115
        // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
116
        // the lockout authorization will be reset at startup.
117
        if(gp.lockoutRecovery != 0)
4✔
118
        {
119
            if(NV_IS_AVAILABLE)
4✔
120
                // Update NV.
121
                NV_SYNC_PERSISTENT(lockOutAuthEnabled);
4✔
122
            else
123
                // No NV access for now. Put the TPM in pending mode.
UNCOV
124
                s_DAPendingOnNV = TRUE;
×
125
        }
126
    }
127
    else
128
    {
129
        if(gp.recoveryTime != 0)
16✔
130
        {
131
            gp.failedTries++;
15✔
132
            if(NV_IS_AVAILABLE)
15✔
133
                // Record changes to NV. NvWrite will SET g_updateNV
134
                NV_SYNC_PERSISTENT(failedTries);
15✔
135
            else
136
                // No NV access for now.  Put the TPM in pending mode.
UNCOV
137
                s_DAPendingOnNV = TRUE;
×
138
        }
139
    }
140
    // Register a DA failure and reset the timers.
141
    DARegisterFailure(handle);
20✔
142

143
    return TPM_RC_AUTH_FAIL;
20✔
144
}
145

146
//*** IsSessionBindEntity()
147
// This function indicates if the entity associated with the handle is the entity,
148
// to which this session is bound. The binding would occur by making the "bind"
149
// parameter in TPM2_StartAuthSession() not equal to TPM_RH_NULL. The binding only
150
// occurs if the session is an HMAC session. The bind value is a combination of
151
// the Name and the authValue of the entity.
152
//
153
//  Return Type: BOOL
154
//      TRUE(1)         handle points to the session start entity
155
//      FALSE(0)        handle does not point to the session start entity
156
static BOOL IsSessionBindEntity(
772✔
157
    TPM_HANDLE associatedHandle,  // IN: handle to be authorized
158
    SESSION*   session            // IN: associated session
159
)
160
{
161
    TPM2B_NAME entity;  // The bind value for the entity
772✔
162
                        //
163
    // If the session is not bound, return FALSE.
164
    if(session->attributes.isBound)
772✔
165
    {
166
        // Compute the bind value for the entity.
167
        SessionComputeBoundEntity(associatedHandle, &entity);
60✔
168

169
        // Compare to the bind value in the session.
170
        return MemoryEqual2B(&entity.b, &session->u1.boundEntity.b);
60✔
171
    }
172
    return FALSE;
173
}
174

175
//*** IsPolicySessionRequired()
176
// Checks if a policy session is required for a command. If a command requires
177
// DUP or ADMIN role authorization, then the handle that requires that role is the
178
// first handle in the command. This simplifies this checking. If a new command
179
// is created that requires multiple ADMIN role authorizations, then it will
180
// have to be special-cased in this function.
181
// A policy session is required if:
182
// a) the command requires the DUP role;
183
// b) the command requires the ADMIN role and the authorized entity
184
//    is an object and its adminWithPolicy bit is SET;
185
// c) the command requires the ADMIN role and the authorized entity
186
//    is a permanent handle or an NV Index; or
187
// d) the authorized entity is a PCR belonging to a policy group, and
188
//    has its policy initialized
189
//  Return Type: BOOL
190
//      TRUE(1)         policy session is required
191
//      FALSE(0)        policy session is not required
192
static BOOL IsPolicySessionRequired(COMMAND_INDEX commandIndex,  // IN: command index
6,436✔
193
                                    UINT32        sessionIndex   // IN: session index
194
)
195
{
196
    AUTH_ROLE role = CommandAuthRole(commandIndex, sessionIndex);
6,436✔
197
    TPM_HT    type = HandleGetType(s_associatedHandles[sessionIndex]);
6,436✔
198
    //
199
    if(role == AUTH_DUP)
6,436✔
200
        return TRUE;
201
    if(role == AUTH_ADMIN)
6,436✔
202
    {
203
        // We allow an exception for ADMIN role in a transient object. If the object
204
        // allows ADMIN role actions with authorization, then policy is not
205
        // required. For all other cases, there is no way to override the command
206
        // requirement that a policy be used
207
        if(type == TPM_HT_TRANSIENT)
284✔
208
        {
209
            OBJECT* object = HandleToObject(s_associatedHandles[sessionIndex]);
271✔
210

211
            if(!IS_ATTRIBUTE(
271✔
212
                   object->publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy))
213
                return FALSE;
214
        }
215
        return TRUE;
13✔
216
    }
217

218
    if(type == TPM_HT_PCR)
6,152✔
219
    {
220
        if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex]))
276✔
221
        {
UNCOV
222
            TPM2B_DIGEST  policy;
×
UNCOV
223
            TPMI_ALG_HASH policyAlg;
×
UNCOV
224
            policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], &policy);
×
UNCOV
225
            if(policyAlg != TPM_ALG_NULL)
×
UNCOV
226
                return TRUE;
×
227
        }
228
    }
229
    return FALSE;
230
}
231

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

279
#ifndef __ACT_DISABLED        // libtpms changed
280
                    FOR_EACH_ACT(CASE_ACT_HANDLE)
281
                    {
282
                        // The ACT auth value is not available if the platform is disabled
283
                        result = g_phEnable == SET;
284
                        break;
285
                    }
286
#endif  // ACT_SUPPORT
287

288
                default:
289
                    // Otherwise authValue is not available.
290
                    break;
291
            }
292
            break;
293
        case TPM_HT_TRANSIENT:
1,960✔
294
            // A persistent object has already been loaded and the internal
295
            // handle changed.
296
            {
297
                OBJECT*     object;
1,960✔
298
                TPMA_OBJECT attributes;
1,960✔
299
                //
300
                object     = HandleToObject(handle);
1,960✔
301
                attributes = object->publicArea.objectAttributes;
1,960✔
302

303
                // authValue is always available for a sequence object.
304
                // An alternative for this is to
305
                // SET_ATTRIBUTE(object->publicArea, TPMA_OBJECT, userWithAuth) when the
306
                // sequence is started.
307
                if(ObjectIsSequence(object))
1,960✔
308
                {
309
                    result = TRUE;
310
                    break;
311
                }
312
                // authValue is available for an object if it has its sensitive
313
                // portion loaded and
314
                //  a) userWithAuth bit is SET, or
315
                //  b) ADMIN role is required
316
                if(object->attributes.publicOnly == CLEAR
1,851✔
317
                   && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, userWithAuth)
1,851✔
318
                       || (CommandAuthRole(commandIndex, sessionIndex) == AUTH_ADMIN
8✔
UNCOV
319
                           && !IS_ATTRIBUTE(
×
320
                               attributes, TPMA_OBJECT, adminWithPolicy))))
321
                    result = TRUE;
322
            }
323
            break;
324
        case TPM_HT_NV_INDEX:
506✔
325
            // NV Index.
326
            {
327
                NV_REF    locator;
506✔
328
                NV_INDEX* nvIndex = NvGetIndexInfo(handle, &locator);
506✔
329
                TPMA_NV   nvAttributes;
506✔
330
                //
331
                pAssert(nvIndex != 0);
506✔
332

333
                nvAttributes = nvIndex->publicArea.attributes;
506✔
334

335
                if(IsWriteOperation(commandIndex))
506✔
336
                {
337
                    // AuthWrite can't be set for a PIN index
338
                    if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHWRITE))
224✔
339
                        result = TRUE;
220✔
340
                }
341
                else
342
                {
343
                    // A "read" operation
344
                    // For a PIN Index, the authValue is available as long as the
345
                    // Index has been written and the pinCount is less than pinLimit
346
                    if(IsNvPinFailIndex(nvAttributes)
282✔
347
                       || IsNvPinPassIndex(nvAttributes))
282✔
348
                    {
349
                        NV_PIN pin;
32✔
350
                        if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
32✔
351
                            break;  // return false
352
                        // get the index values
353
                        pin.intVal = NvGetUINT64Data(nvIndex, locator);
31✔
354
                        if(pin.pin.pinCount < pin.pin.pinLimit)
31✔
355
                            result = TRUE;
21✔
356
                    }
357
                    // For non-PIN Indexes, need to allow use of the authValue
358
                    else if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHREAD))
250✔
359
                        result = TRUE;
246✔
360
                }
361
            }
362
            break;
505✔
363
        case TPM_HT_PCR:
276✔
364
            // PCR handle.
365
            // authValue is always allowed for PCR
366
            result = TRUE;
276✔
367
            break;
276✔
368
        default:
369
            // Otherwise, authValue is not available
370
            break;
371
    }
372
    return result;
6,396✔
373
}
374

375
//*** IsAuthPolicyAvailable()
376
// This function indicates if an authPolicy is available and allowed.
377
//
378
// This function does not check that the handle reference is valid or if the entity
379
// is in an enabled hierarchy. Those checks are assumed to have been performed
380
// during the handle unmarshaling.
381
//
382
//  Return Type: BOOL
383
//      TRUE(1)         authPolicy is available
384
//      FALSE(0)        authPolicy is not available
385
static BOOL IsAuthPolicyAvailable(TPM_HANDLE    handle,        // IN: handle of entity
208✔
386
                                  COMMAND_INDEX commandIndex,  // IN: command index
387
                                  UINT32        sessionIndex   // IN: session index
388
)
389
{
390
    BOOL result = FALSE;
208✔
391
    //
392
    switch(HandleGetType(handle))
208✔
393
    {
394
        case TPM_HT_PERMANENT:
7✔
395
            switch(handle)
7✔
396
            {
397
                // At this point hierarchy availability has already been checked.
UNCOV
398
                case TPM_RH_OWNER:
×
UNCOV
399
                    if(gp.ownerPolicy.t.size != 0)
×
UNCOV
400
                        result = TRUE;
×
401
                    break;
UNCOV
402
                case TPM_RH_ENDORSEMENT:
×
UNCOV
403
                    if(gp.endorsementPolicy.t.size != 0)
×
UNCOV
404
                        result = TRUE;
×
405
                    break;
406
                case TPM_RH_PLATFORM:
7✔
407
                    if(gc.platformPolicy.t.size != 0)
7✔
408
                        result = TRUE;
7✔
409
                    break;
410
#if ACT_SUPPORT || 1        // libtpms changed
411

412
#  define ACT_GET_POLICY(N)                     \
413
      case TPM_RH_ACT_##N:                      \
414
          if(go.ACT_##N.authPolicy.t.size != 0) \
415
              result = TRUE;                    \
416
          break;
417

418
                    FOR_EACH_ACT(ACT_GET_POLICY)
419
#endif  // ACT_SUPPORT
420

421
                case TPM_RH_LOCKOUT:
×
422
                    if(gp.lockoutPolicy.t.size != 0)
×
UNCOV
423
                        result = TRUE;
×
424
                    break;
425
                default:
426
                    break;
427
            }
428
            break;
429
        case TPM_HT_TRANSIENT:
163✔
430
        {
431
            // Object handle.
432
            // An evict object would already have been loaded and given a
433
            // transient object handle by this point.
434
            OBJECT* object = HandleToObject(handle);
163✔
435
            // Policy authorization is not available for an object with only
436
            // public portion loaded.
437
            if(object->attributes.publicOnly == CLEAR)
163✔
438
            {
439
                // Policy authorization is always available for an object but
440
                // is never available for a sequence.
441
                if(!ObjectIsSequence(object))
163✔
442
                    result = TRUE;
163✔
443
            }
444
            break;
445
        }
446
        case TPM_HT_NV_INDEX:
38✔
447
            // An NV Index.
448
            {
449
                NV_INDEX* nvIndex      = NvGetIndexInfo(handle, NULL);
38✔
450
                TPMA_NV   nvAttributes = nvIndex->publicArea.attributes;
38✔
451
                //
452
                // If the policy size is not zero, check if policy can be used.
453
                if(nvIndex->publicArea.authPolicy.t.size != 0)
38✔
454
                {
455
                    // If policy session is required for this handle, always
456
                    // uses policy regardless of the attributes bit setting
457
                    if(IsPolicySessionRequired(commandIndex, sessionIndex))
38✔
458
                        result = TRUE;
459
                    // Otherwise, the presence of the policy depends on the NV
460
                    // attributes.
461
                    else if(IsWriteOperation(commandIndex))
27✔
462
                    {
463
                        if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYWRITE))
19✔
464
                            result = TRUE;
19✔
465
                    }
466
                    else
467
                    {
468
                        if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYREAD))
8✔
469
                            result = TRUE;
8✔
470
                    }
471
                }
472
            }
473
            break;
UNCOV
474
        case TPM_HT_PCR:
×
475
            // PCR handle.
UNCOV
476
            if(PCRPolicyIsAvailable(handle))
×
UNCOV
477
                result = TRUE;
×
478
            break;
479
        default:
480
            break;
481
    }
482
    return result;
208✔
483
}
484

485
//**  Session Parsing Functions
486

487
//*** ClearCpRpHashes()
488
void ClearCpRpHashes(COMMAND* command)
16,850✔
489
{
490
    // The macros expand according to the implemented hash algorithms. An IDE may
491
    // complain that COMMAND does not contain SHA1CpHash or SHA1RpHash because of the
492
    // complexity of the macro expansion where the data space is defined; but, if SHA1
493
    // is implemented, it actually does  and the compiler is happy.
494
#define CLEAR_CP_HASH(HASH, Hash) command->Hash##CpHash.b.size = 0;
495
    FOR_EACH_HASH(CLEAR_CP_HASH)
16,850✔
496
#define CLEAR_RP_HASH(HASH, Hash) command->Hash##RpHash.b.size = 0;
497
    FOR_EACH_HASH(CLEAR_RP_HASH)
16,850✔
498
}
16,850✔
499

500
//*** GetCpHashPointer()
501
// Function to get a pointer to the cpHash of the command
502
static TPM2B_DIGEST* GetCpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,055✔
503
{
504
    TPM2B_DIGEST* retVal;
1,055✔
505
//
506
// Define the macro that will expand for each implemented algorithm in the switch
507
// statement below.
508
#define GET_CP_HASH_POINTER(HASH, Hash)                 \
509
    case ALG_##HASH##_VALUE:                            \
510
        retVal = (TPM2B_DIGEST*)&command->Hash##CpHash; \
511
        break;
512

513
    switch(hashAlg)
1,055✔
514
    {
515
        // For each implemented hash, this will expand as defined above
516
        // by GET_CP_HASH_POINTER. Your IDE may complain that
517
        // 'struct "COMMAND" has no field "SHA1CpHash"' but the compiler says
518
        // it does, so...
519
        FOR_EACH_HASH(GET_CP_HASH_POINTER)
1,055✔
520
        default:
521
            retVal = NULL;
522
            break;
523
    }
524
    return retVal;
1,055✔
525
}
526

527
//*** GetRpHashPointer()
528
// Function to get a pointer to the RpHash of the command
529
static TPM2B_DIGEST* GetRpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg)
1,026✔
530
{
531
    TPM2B_DIGEST* retVal;
1,026✔
532
//
533
// Define the macro that will expand for each implemented algorithm in the switch
534
// statement below.
535
#define GET_RP_HASH_POINTER(HASH, Hash)                 \
536
    case ALG_##HASH##_VALUE:                            \
537
        retVal = (TPM2B_DIGEST*)&command->Hash##RpHash; \
538
        break;
539

540
    switch(hashAlg)
1,026✔
541
    {
542
        // For each implemented hash, this will expand as defined above
543
        // by GET_RP_HASH_POINTER. Your IDE may complain that
544
        // 'struct "COMMAND" has no field 'SHA1RpHash'" but the compiler says
545
        // it does, so...
546
        FOR_EACH_HASH(GET_RP_HASH_POINTER)
1,026✔
547
        default:
548
            retVal = NULL;
549
            break;
550
    }
551
    return retVal;
1,026✔
552
}
553

554
//*** ComputeCpHash()
555
// This function computes the cpHash as defined in Part 2 and described in Part 1.
556
static TPM2B_DIGEST* ComputeCpHash(COMMAND* command,  // IN: command parsing structure
1,003✔
557
                                   TPMI_ALG_HASH hashAlg  // IN: hash algorithm
558
)
559
{
560
    UINT32        i;
1,003✔
561
    HASH_STATE    hashState;
1,003✔
562
    TPM2B_NAME    name;
1,003✔
563
    TPM2B_DIGEST* cpHash;
1,003✔
564
    //
565
    // cpHash = hash(commandCode [ || authName1
566
    //                           [ || authName2
567
    //                           [ || authName 3 ]]]
568
    //                           [ || parameters])
569
    // A cpHash can contain just a commandCode only if the lone session is
570
    // an audit session.
571
    // Get pointer to the hash value
572
    cpHash = GetCpHashPointer(command, hashAlg);
1,003✔
573
    if(cpHash->t.size == 0)
1,003✔
574
    {
575
        cpHash->t.size = CryptHashStart(&hashState, hashAlg);
726✔
576
        //  Add commandCode.
577
        CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
726✔
578
        //  Add authNames for each of the handles.
579
        for(i = 0; i < command->handleNum; i++)
2,553✔
580
            CryptDigestUpdate2B(&hashState,
2,202✔
581
                                &EntityGetName(command->handles[i], &name)->b);
1,101✔
582
        //  Add the parameters.
583
        CryptDigestUpdate(
726✔
584
            &hashState, command->parameterSize, command->parameterBuffer);
726✔
585
        //  Complete the hash.
586
        CryptHashEnd2B(&hashState, &cpHash->b);
726✔
587
    }
588
    return cpHash;
1,003✔
589
}
590

591
//*** GetCpHash()
592
// This function is used to access a precomputed cpHash.
593
static TPM2B_DIGEST* GetCpHash(COMMAND* command, TPMI_ALG_HASH hashAlg)
52✔
594
{
595
    TPM2B_DIGEST* cpHash = GetCpHashPointer(command, hashAlg);
52✔
596
    //
597
    pAssert(cpHash->t.size != 0);
52✔
598
    return cpHash;
52✔
599
}
600

601
//*** CompareTemplateHash()
602
// This function computes the template hash and compares it to the session
603
// templateHash. It is the hash of the second parameter
604
// assuming that the command is TPM2_Create(), TPM2_CreatePrimary(), or
605
// TPM2_CreateLoaded()
606
//  Return Type: BOOL
607
//      TRUE(1)         template hash equal to session->templateHash
608
//      FALSE(0)        template hash not equal to session->templateHash
609
static BOOL CompareTemplateHash(COMMAND* command,  // IN: parsing structure
3✔
610
                                SESSION* session   // IN: session data
611
)
612
{
613
    BYTE*        pBuffer = command->parameterBuffer;
3✔
614
    INT32        pSize   = command->parameterSize;
3✔
615
    TPM2B_DIGEST tHash;
3✔
616
    UINT16       size;
3✔
617
    //
618
    // Only try this for the three commands for which it is intended
619
    if(command->code != TPM_CC_Create && command->code != TPM_CC_CreatePrimary
3✔
620
#if CC_CreateLoaded
621
       && command->code != TPM_CC_CreateLoaded
1✔
622
#endif
623
    )
624
        return FALSE;
625
    // Assume that the first parameter is a TPM2B and unmarshal the size field
626
    // Note: this will not affect the parameter buffer and size in the calling
627
    // function.
628
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
629
        return FALSE;
630
    // reduce the space in the buffer.
631
    // NOTE: this could make pSize go negative if the parameters are not correct but
632
    // the unmarshaling code does not try to unmarshal if the remaining size is
633
    // negative.
634
    pSize -= size;
3✔
635

636
    // Advance the pointer
637
    pBuffer += size;
3✔
638

639
    // Get the size of what should be the template
640
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
641
        return FALSE;
642
    // See if this is reasonable
643
    if(size > pSize)
3✔
644
        return FALSE;
645
    // Hash the template data
646
    tHash.t.size = CryptHashBlock(
6✔
647
        session->authHashAlg, size, pBuffer, sizeof(tHash.t.buffer), tHash.t.buffer);
3✔
648
    return (MemoryEqual2B(&session->u1.templateHash.b, &tHash.b));
3✔
649
}
650

651
//*** CompareNameHash()
652
// This function computes the name hash and compares it to the nameHash in the
653
// session data, returning true if they are equal.
654
BOOL CompareNameHash(COMMAND* command,  // IN: main parsing structure
3✔
655
                     SESSION* session   // IN: session structure with nameHash
656
)
657
{
658
    HASH_STATE   hashState;
3✔
659
    TPM2B_DIGEST nameHash;
3✔
660
    UINT32       i;
3✔
661
    TPM2B_NAME   name;
3✔
662
    //
663
    nameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
664
    //  Add names.
665
    for(i = 0; i < command->handleNum; i++)
8✔
666
        CryptDigestUpdate2B(&hashState,
10✔
667
                            &EntityGetName(command->handles[i], &name)->b);
5✔
668
    //  Complete hash.
669
    CryptHashEnd2B(&hashState, &nameHash.b);
3✔
670
    // and compare
671
    return MemoryEqual(
6✔
672
        session->u1.nameHash.t.buffer, nameHash.t.buffer, nameHash.t.size);
3✔
673
}
674

675
//*** CompareParametersHash()
676
// This function computes the parameters hash and compares it to the pHash in
677
// the session data, returning true if they are equal.
678
BOOL CompareParametersHash(COMMAND* command,  // IN: main parsing structure
3✔
679
                           SESSION* session   // IN: session structure with pHash
680
)
681
{
682
    HASH_STATE   hashState;
3✔
683
    TPM2B_DIGEST pHash;
3✔
684
    //
685
    pHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
3✔
686
    //  Add commandCode.
687
    CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
3✔
688
    //  Add the parameters.
689
    CryptDigestUpdate(&hashState, command->parameterSize, command->parameterBuffer);
3✔
690
    //  Complete hash.
691
    CryptHashEnd2B(&hashState, &pHash.b);
3✔
692
    // and compare
693
    return MemoryEqual2B(&session->u1.pHash.b, &pHash.b);
3✔
694
}
695

696
#if SEC_CHANNEL_SUPPORT
697
//*** CompareScKeyNameHash()
698
// This function computes the secure channel key name hash (from the requester and/or TPM key
699
// used to establish the secure channel session) and compares it to the scKeyNameHash in the
700
// session data, returning true if they are equal.
701
BOOL CompareScKeyNameHash(
702
    SESSION*    session,     // IN: session structure
703
    TPM2B_NAME* reqKeyName,  // IN: requester secure channel key name
704
    TPM2B_NAME* tpmKeyName   // IN: TPM secure channel key name
705
)
706
{
707
    HASH_STATE   hashState;
708
    TPM2B_DIGEST scKeyNameHash;
709
    UINT16       zeroSize = 0x0000;
710

711
    // Compute secure channel key name hash
712
    // scKeyNameHash = hash(reqKeyName.size || reqKeyName.name || tpmKeyName.size || tpmKeyName.name)
713
    //  Start hash
714
    scKeyNameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
715

716
    //  Include reqKeyName if it needs to be checked, otherwise include Empty Buffer
717
    if(session->attributes.checkReqKey)
718
    {
719
        //  Add reqKeyName.size
720
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), reqKeyName->t.size);
721

722
        //  Add reqKeyName.name
723
        CryptDigestUpdate2B(&hashState, &reqKeyName->b);
724
    }
725
    else
726
    {
727
        //  Add zero size
728
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
729
    }
730

731
    //  Include tpmKeyName if it needs to be checked, otherwise include Empty Buffer
732
    if(session->attributes.checkTpmKey)
733
    {
734
        //  Add tpmKeyName.size
735
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), tpmKeyName->t.size);
736

737
        //  Add tpmKeyName.name
738
        CryptDigestUpdate2B(&hashState, &tpmKeyName->b);
739
    }
740
    else
741
    {
742
        //  Add zero size
743
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
744
    }
745

746
    //  Complete hash
747
    CryptHashEnd2B(&hashState, &scKeyNameHash.b);
748

749
    // and compare
750
    return MemoryEqual(session->scKeyNameHash.t.buffer,
751
                       scKeyNameHash.t.buffer,
752
                       scKeyNameHash.t.size);
753
}
754
#endif  // SEC_CHANNEL_SUPPORT
755

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

777
    // Get the authValue with trailing zeros removed
778
    EntityGetAuthValue(associatedHandle, &authValue);
5,607✔
779

780
    // Success if the values are identical.
781
    if(MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &authValue.b))
5,607✔
782
    {
783
        return TPM_RC_SUCCESS;
784
    }
785
    else  // if the digests are not identical
786
    {
787
        // Invoke DA protection if applicable.
788
        return IncrementLockout(sessionIndex);
79✔
789
    }
790
}
791

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

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

881
    // Continue with the HMAC processing.
882
    session = SessionGet(s_sessionHandles[sessionIndex]);
1,028✔
883

884
    // Generate HMAC key.
885
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1,028✔
886

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

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

929
    return hmac;
899✔
930
}
931

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

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

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

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

1023
    // Compare policy hash algorithm.
1024
    if(policyAlg != session->authHashAlg)
173✔
1025
        return TPM_RC_POLICY_FAIL;
1026

1027
    // Compare timeout.
1028
    if(session->timeout != 0)
173✔
1029
    {
1030
        // Cannot compare time if clock stop advancing.  An TPM_RC_NV_UNAVAILABLE
1031
        // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that
1032
        // a new nonce will be created just that, because TPM time can't advance
1033
        // we can't do time-based operations.
1034
        RETURN_IF_NV_IS_NOT_AVAILABLE;
11✔
1035

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

1058
        // Get existing locality setting in canonical form
1059
        sessionLocality[0] = 0;
170✔
1060
        TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
170✔
1061

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

1121
        // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
1122
        if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
4✔
1123
           != (session->attributes.nvWrittenState == SET))
4✔
1124
            return TPM_RC_POLICY_FAIL;
1125
    }
1126
#if SEC_CHANNEL_SUPPORT
1127
    if(session->attributes.checkSecureChannel)
1128
    {
1129
        TPM2B_NAME reqKeyName;
1130
        TPM2B_NAME tpmKeyName;
1131

1132
        // Check that the authorized TPM command is protected by an SPDM session and
1133
        // if so, get the names of the associated requester and TPM key
1134
        if(!IsSpdmSessionActive(&reqKeyName, &tpmKeyName))
1135
            return TPM_RC_CHANNEL;
1136

1137
        // If required, check the requester or TPM secure channel key name by comparing scKeyNameHash
1138
        if(session->attributes.checkReqKey == SET
1139
           || session->attributes.checkTpmKey == SET)
1140
        {
1141
            if(!CompareScKeyNameHash(session, &reqKeyName, &tpmKeyName))
1142
                return TPM_RC_CHANNEL_KEY;
1143
        }
1144
    }
1145
#endif  // SEC_CHANNEL_SUPPORT
1146
    return TPM_RC_SUCCESS;
1147
}
1148

1149
//*** RetrieveSessionData()
1150
// This function will unmarshal the sessions in the session area of a command. The
1151
// values are placed in the arrays that are defined at the beginning of this file.
1152
// The normal unmarshaling errors are possible.
1153
//
1154
//  Return Type: TPM_RC
1155
//      TPM_RC_SUCCSS       unmarshaled without error
1156
//      TPM_RC_SIZE         the number of bytes unmarshaled is not the same
1157
//                          as the value for authorizationSize in the command
1158
//
1159
static TPM_RC RetrieveSessionData(
6,308✔
1160
    COMMAND* command  // IN: main parsing structure for command
1161
)
1162
{
1163
    int          i;
6,308✔
1164
    TPM_RC       result;
6,308✔
1165
    SESSION*     session;
6,308✔
1166
    TPMA_SESSION sessionAttributes;
6,308✔
1167
    TPM_HT       sessionType;
6,308✔
1168
    INT32        sessionIndex;
6,308✔
1169
    TPM_RC       errorIndex;
6,308✔
1170
    //
1171
    s_decryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1172
    s_encryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1173
    s_auditSessionIndex   = UNDEFINED_INDEX;
6,308✔
1174

1175
    for(sessionIndex = 0; command->authSize > 0; sessionIndex++)
13,105✔
1176
    {
1177
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,847✔
1178

1179
        // If maximum allowed number of sessions has been parsed, return a size
1180
        // error with a session number that is larger than the number of allowed
1181
        // sessions
1182
        if(sessionIndex == MAX_SESSION_NUM)
6,847✔
1183
            return TPM_RCS_SIZE + errorIndex;
4✔
1184
        // make sure that the associated handle for each session starts out
1185
        // unassigned
1186
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
6,843✔
1187

1188
        // First parameter: Session handle.
1189
        result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
6,843✔
1190
                                                &command->parameterBuffer,
1191
                                                &command->authSize,
1192
                                                TRUE);
1193
        if(result != TPM_RC_SUCCESS)
6,843✔
1194
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
16✔
1195
        // Second parameter: Nonce.
1196
        result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
6,827✔
1197
                                       &command->parameterBuffer,
1198
                                       &command->authSize);
1199
        if(result != TPM_RC_SUCCESS)
6,827✔
1200
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
8✔
1201
        // Third parameter: sessionAttributes.
1202
        result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
6,819✔
1203
                                        &command->parameterBuffer,
1204
                                        &command->authSize);
1205
        if(result != TPM_RC_SUCCESS)
6,819✔
1206
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
4✔
1207
        // Fourth parameter: authValue (PW or HMAC).
1208
        result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
6,815✔
1209
                                      &command->parameterBuffer,
1210
                                      &command->authSize);
1211
        if(result != TPM_RC_SUCCESS)
6,815✔
1212
            return result + errorIndex;
4✔
1213

1214
        sessionAttributes = s_attributes[sessionIndex];
6,811✔
1215
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,811✔
1216
        {
1217
            // A PWAP session needs additional processing.
1218
            //     Can't have any attributes set other than continueSession bit
1219
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)
5,726✔
1220
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)
1221
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)
5,726✔
1222
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
1223
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset))
5,722✔
1224
                return TPM_RCS_ATTRIBUTES + errorIndex;
4✔
1225
            //     The nonce size must be zero.
1226
            if(s_nonceCaller[sessionIndex].t.size != 0)
5,722✔
1227
                return TPM_RCS_NONCE + errorIndex;
4✔
1228
            continue;
5,718✔
1229
        }
1230
        // For not password sessions...
1231
        // Find out if the session is loaded.
1232
        if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
1,085✔
1233
            return TPM_RC_REFERENCE_S0 + sessionIndex;
6✔
1234
        sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
1,079✔
1235
        session     = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1236

1237
        // Check if the session is an HMAC/policy session.
1238
        if((session->attributes.isPolicy == SET && sessionType == TPM_HT_HMAC_SESSION)
1,079✔
1239
           || (session->attributes.isPolicy == CLEAR
1,079✔
1240
               && sessionType == TPM_HT_POLICY_SESSION))
871✔
UNCOV
1241
            return TPM_RCS_HANDLE + errorIndex;
×
1242
        // Check that this handle has not previously been used.
1243
        for(i = 0; i < sessionIndex; i++)
1,410✔
1244
        {
1245
            if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
331✔
UNCOV
1246
                return TPM_RCS_HANDLE + errorIndex;
×
1247
        }
1248
        // If the session is used for parameter encryption or audit as well, set
1249
        // the corresponding Indexes.
1250

1251
        // First process decrypt.
1252
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt))
1,079✔
1253
        {
1254
            // Check if the commandCode allows command parameter encryption.
1255
            if(DecryptSize(command->index) == 0)
162✔
UNCOV
1256
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1257
            // Encrypt attribute can only appear in one session
1258
            if(s_decryptSessionIndex != UNDEFINED_INDEX)
162✔
UNCOV
1259
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1260
            // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
1261
            if(session->symmetric.algorithm == TPM_ALG_NULL)
162✔
UNCOV
1262
                return TPM_RCS_SYMMETRIC + errorIndex;
×
1263
            // All checks passed, so set the index for the session used to decrypt
1264
            // a command parameter.
1265
            s_decryptSessionIndex = sessionIndex;
162✔
1266
        }
1267
        // Now process encrypt.
1268
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt))
1,079✔
1269
        {
1270
            // Check if the commandCode allows response parameter encryption.
1271
            if(EncryptSize(command->index) == 0)
154✔
UNCOV
1272
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1273
            // Encrypt attribute can only appear in one session.
1274
            if(s_encryptSessionIndex != UNDEFINED_INDEX)
154✔
UNCOV
1275
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1276
            // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
1277
            if(session->symmetric.algorithm == TPM_ALG_NULL)
154✔
UNCOV
1278
                return TPM_RCS_SYMMETRIC + errorIndex;
×
1279
            // All checks passed, so set the index for the session used to encrypt
1280
            // a response parameter.
1281
            s_encryptSessionIndex = sessionIndex;
154✔
1282
        }
1283
        // At last process audit.
1284
        if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit))
1,079✔
1285
        {
1286
            // Audit attribute can only appear in one session.
1287
            if(s_auditSessionIndex != UNDEFINED_INDEX)
35✔
UNCOV
1288
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1289
            // An audit session can not be policy session.
1290
            if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION)
35✔
UNCOV
1291
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1292
            // If this is a reset of the audit session, or the first use
1293
            // of the session as an audit session, it doesn't matter what
1294
            // the exclusive state is. The session will become exclusive.
1295
            if(!IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset)
35✔
1296
               && session->attributes.isAudit == SET)
35✔
1297
            {
1298
                // Not first use or reset. If auditExlusive is SET, then this
1299
                // session must be the current exclusive session.
1300
                if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
14✔
UNCOV
1301
                   && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
×
1302
                    return TPM_RC_EXCLUSIVE;
1303
            }
1304
            s_auditSessionIndex = sessionIndex;
35✔
1305
        }
1306
        // Initialize associated handle as undefined. This will be changed when
1307
        // the handles are processed.
1308
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1,079✔
1309
    }
1310
    command->sessionNum = sessionIndex;
6,258✔
1311
    return TPM_RC_SUCCESS;
6,258✔
1312
}
1313

1314
//*** CheckLockedOut()
1315
// This function checks to see if the TPM is in lockout. This function should only
1316
// be called if the entity being checked is subject to DA protection. The TPM
1317
// is in lockout if the NV is not available and a DA write is pending. Otherwise
1318
// the TPM is locked out if checking for lockoutAuth ('lockoutAuthCheck' == TRUE)
1319
// and use of lockoutAuth is disabled, or 'failedTries' >= 'maxTries'
1320
//  Return Type: TPM_RC
1321
//      TPM_RC_NV_RATE          NV is rate limiting
1322
//      TPM_RC_NV_UNAVAILABLE   NV is not available at this time
1323
//      TPM_RC_LOCKOUT          TPM is in lockout
1324
static TPM_RC CheckLockedOut(
158✔
1325
    BOOL lockoutAuthCheck  // IN: TRUE if checking is for lockoutAuth
1326
)
1327
{
1328
    // If NV is unavailable, and current cycle state recorded in NV is not
1329
    // SU_NONE_VALUE, refuse to check any authorization because we would
1330
    // not be able to handle a DA failure.
1331
    if(!NV_IS_AVAILABLE && NV_IS_ORDERLY)
158✔
1332
        return g_NvStatus;
1333
    // Check if DA info needs to be updated in NV.
1334
    if(s_DAPendingOnNV)
158✔
1335
    {
1336
        // If NV is accessible,
UNCOV
1337
        RETURN_IF_NV_IS_NOT_AVAILABLE;
×
1338

1339
        // ... write the pending DA data and proceed.
UNCOV
1340
        NV_SYNC_PERSISTENT(lockOutAuthEnabled);
×
UNCOV
1341
        NV_SYNC_PERSISTENT(failedTries);
×
UNCOV
1342
        s_DAPendingOnNV = FALSE;
×
1343
    }
1344
    // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1345
    // is disabled...
1346
    if(lockoutAuthCheck)
158✔
1347
    {
1348
        if(gp.lockOutAuthEnabled == FALSE)
80✔
UNCOV
1349
            return TPM_RC_LOCKOUT;
×
1350
    }
1351
    else
1352
    {
1353
        // ... or if the number of failed tries has been maxed out.
1354
        if(gp.failedTries >= gp.maxTries)
78✔
1355
            return TPM_RC_LOCKOUT;
1356
#if USE_DA_USED
1357
        // If the daUsed flag is not SET, then no DA validation until the
1358
        // daUsed state is written to NV
1359
        if(!g_daUsed)
40✔
1360
        {
1361
            RETURN_IF_NV_IS_NOT_AVAILABLE;
10✔
1362
            g_daUsed        = TRUE;
10✔
1363
            gp.orderlyState = SU_DA_USED_VALUE;
10✔
1364
            NV_SYNC_PERSISTENT(orderlyState);
10✔
1365
            return TPM_RC_SUCCESS; // libtpms changed: was TPM_RC_RETRY;
10✔
1366
        }
1367
#endif
1368
    }
1369
    return TPM_RC_SUCCESS;
1370
}
1371

1372
//*** CheckAuthSession()
1373
// This function checks that the authorization session properly authorizes the
1374
// use of the associated handle.
1375
//
1376
//  Return Type: TPM_RC
1377
//      TPM_RC_LOCKOUT              entity is protected by DA and TPM is in
1378
//                                  lockout, or TPM is locked out on NV update
1379
//                                  pending on DA parameters
1380
//
1381
//      TPM_RC_PP                   Physical Presence is required but not provided
1382
//      TPM_RC_AUTH_FAIL            HMAC or PW authorization failed
1383
//                                  with DA side-effects (can be a policy session)
1384
//
1385
//      TPM_RC_BAD_AUTH             HMAC or PW authorization failed without DA
1386
//                                  side-effects (can be a policy session)
1387
//
1388
//      TPM_RC_POLICY_FAIL          if policy session fails
1389
//      TPM_RC_POLICY_CC            command code of policy was wrong
1390
//      TPM_RC_EXPIRED              the policy session has expired
1391
//      TPM_RC_PCR
1392
//      TPM_RC_AUTH_UNAVAILABLE     authValue or authPolicy unavailable
1393
static TPM_RC CheckAuthSession(
6,656✔
1394
    COMMAND* command,      // IN: primary parsing structure
1395
    UINT32   sessionIndex  // IN: index of session to be processed
1396
)
1397
{
1398
    TPM_RC     result            = TPM_RC_SUCCESS;
6,656✔
1399
    SESSION*   session           = NULL;
6,656✔
1400
    TPM_HANDLE sessionHandle     = s_sessionHandles[sessionIndex];
6,656✔
1401
    TPM_HANDLE associatedHandle  = s_associatedHandles[sessionIndex];
6,656✔
1402
    TPM_HT     sessionHandleType = HandleGetType(sessionHandle);
6,656✔
1403
    BOOL       authUsed;
6,656✔
1404
    //
1405
    pAssert(sessionHandle != TPM_RH_UNASSIGNED);
6,656✔
1406

1407
    // Take care of physical presence
1408
    if(associatedHandle == TPM_RH_PLATFORM)
6,656✔
1409
    {
1410
        // If the physical presence is required for this command, check for PP
1411
        // assertion. If it isn't asserted, no point going any further.
1412
        if(PhysicalPresenceIsRequired(command->index)
1,023✔
1413
           && !_plat__PhysicalPresenceAsserted())
12✔
1414
            return TPM_RC_PP;
1415
    }
1416
    if(sessionHandle != TPM_RS_PW)
6,644✔
1417
    {
1418
        session = SessionGet(sessionHandle);
980✔
1419

1420
        // Set includeAuth to indicate if DA checking will be required and if the
1421
        // authValue will be included in any HMAC.
1422
        if(sessionHandleType == TPM_HT_POLICY_SESSION)
980✔
1423
        {
1424
            // For a policy session, will check the DA status of the entity if either
1425
            // isAuthValueNeeded or isPasswordNeeded is SET.
1426
            session->attributes.includeAuth = session->attributes.isAuthValueNeeded
208✔
1427
                                              || session->attributes.isPasswordNeeded;
208✔
1428
        }
1429
        else
1430
        {
1431
            // For an HMAC session, need to check unless the session
1432
            // is bound.
1433
            session->attributes.includeAuth =
1,544✔
1434
                !IsSessionBindEntity(s_associatedHandles[sessionIndex], session);
772✔
1435
        }
1436
        authUsed = session->attributes.includeAuth;
980✔
1437
    }
1438
    else
1439
        // Password session
1440
        authUsed = TRUE;
1441
    // If the authorization session is going to use an authValue, then make sure
1442
    // that access to that authValue isn't locked out.
1443
    if(authUsed)
980✔
1444
    {
1445
        // See if entity is subject to lockout.
1446
        if(!IsDAExempted(associatedHandle))
6,409✔
1447
        {
1448
            // See if in lockout
1449
            result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
158✔
1450
            if(result != TPM_RC_SUCCESS)
158✔
1451
                return result;
1452
        }
1453
    }
1454
    // Policy or HMAC+PW?
1455
    if(sessionHandleType != TPM_HT_POLICY_SESSION)
6,606✔
1456
    {
1457
        // for non-policy session make sure that a policy session is not required
1458
        if(IsPolicySessionRequired(command->index, sessionIndex))
6,398✔
1459
            return TPM_RC_AUTH_TYPE;
1460
        // The authValue must be available.
1461
        // Note: The authValue is going to be "used" even if it is an EmptyAuth.
1462
        // and the session is bound.
1463
        if(!IsAuthValueAvailable(associatedHandle, command->index, sessionIndex))
6,396✔
1464
            return TPM_RC_AUTH_UNAVAILABLE;
1465
    }
1466
    else
1467
    {
1468
        // ... see if the entity has a policy, ...
1469
        // Note: IsAuthPolicyAvalable will return FALSE if the sensitive area of the
1470
        // object is not loaded
1471
        if(!IsAuthPolicyAvailable(associatedHandle, command->index, sessionIndex))
208✔
1472
            return TPM_RC_AUTH_UNAVAILABLE;
1473
        // ... and check the policy session.
1474
        result = CheckPolicyAuthSession(command, sessionIndex);
208✔
1475
        if(result != TPM_RC_SUCCESS)
208✔
1476
            return result;
1477
    }
1478
    // Check authorization according to the type
1479
    if((TPM_RS_PW == sessionHandle) || (session->attributes.isPasswordNeeded == SET))
6,536✔
1480
        result = CheckPWAuthSession(sessionIndex);
5,607✔
1481
    else
1482
        result = CheckSessionHMAC(command, sessionIndex);
929✔
1483
    // Do processing for PIN Indexes are only three possibilities for 'result' at
1484
    // this point: TPM_RC_SUCCESS, TPM_RC_AUTH_FAIL, and TPM_RC_BAD_AUTH.
1485
    // For all these cases, we would have to process a PIN index if the
1486
    // authValue of the index was used for authorization.
1487
    if((TPM_HT_NV_INDEX == HandleGetType(associatedHandle)) && authUsed)
6,536✔
1488
    {
1489
        NV_REF    locator;
488✔
1490
        NV_INDEX* nvIndex = NvGetIndexInfo(associatedHandle, &locator);
488✔
1491
        NV_PIN    pinData;
488✔
1492
        TPMA_NV   nvAttributes;
488✔
1493
        //
1494
        pAssert(nvIndex != NULL);
488✔
1495
        nvAttributes = nvIndex->publicArea.attributes;
488✔
1496
        // If this is a PIN FAIL index and the value has been written
1497
        // then we can update the counter (increment or clear)
1498
        if(IsNvPinFailIndex(nvAttributes)
488✔
1499
           && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
13✔
1500
        {
1501
            pinData.intVal = NvGetUINT64Data(nvIndex, locator);
13✔
1502
            if(result != TPM_RC_SUCCESS)
13✔
1503
                pinData.pin.pinCount++;
6✔
1504
            else
1505
                pinData.pin.pinCount = 0;
7✔
1506
            NvWriteUINT64Data(nvIndex, pinData.intVal);
13✔
1507
        }
1508
        // If this is a PIN PASS Index, increment if we have used the
1509
        // authorization value.
1510
        // NOTE: If the counter has already hit the limit, then we
1511
        // would not get here because the authorization value would not
1512
        // be available and the TPM would have returned before it gets here
1513
        else if(IsNvPinPassIndex(nvAttributes)
475✔
1514
                && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN)
8✔
1515
                && result == TPM_RC_SUCCESS)
8✔
1516
        {
1517
            // If the access is valid, then increment the use counter
1518
            pinData.intVal = NvGetUINT64Data(nvIndex, locator);
7✔
1519
            pinData.pin.pinCount++;
7✔
1520
            NvWriteUINT64Data(nvIndex, pinData.intVal);
7✔
1521
        }
1522
    }
1523
    return result;
1524
}
1525

1526
#if CC_GetCommandAuditDigest
1527
//*** CheckCommandAudit()
1528
// This function is called before the command is processed if audit is enabled
1529
// for the command. It will check to see if the audit can be performed and
1530
// will ensure that the cpHash is available for the audit.
1531
//  Return Type: TPM_RC
1532
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
1533
//      TPM_RC_NV_RATE              NV is rate limiting
1534
static TPM_RC CheckCommandAudit(COMMAND* command)
65✔
1535
{
1536
    // If the audit digest is clear and command audit is required, NV must be
1537
    // available so that TPM2_GetCommandAuditDigest() is able to increment
1538
    // audit counter. If NV is not available, the function bails out to prevent
1539
    // the TPM from attempting an operation that would fail anyway.
1540
    if(gr.commandAuditDigest.t.size == 0
65✔
UNCOV
1541
       || GetCommandCode(command->index) == TPM_CC_GetCommandAuditDigest)
×
1542
    {
1543
        RETURN_IF_NV_IS_NOT_AVAILABLE;
65✔
1544
    }
1545
    // Make sure that the cpHash is computed for the algorithm
1546
    ComputeCpHash(command, gp.auditHashAlg);
65✔
1547
    return TPM_RC_SUCCESS;
65✔
1548
}
1549
#endif
1550

1551
//*** ParseSessionBuffer()
1552
// This function is the entry function for command session processing.
1553
// It iterates sessions in session area and reports if the required authorization
1554
// has been properly provided. It also processes audit session and passes the
1555
// information of encryption sessions to parameter encryption module.
1556
//
1557
//  Return Type: TPM_RC
1558
//        various           parsing failure or authorization failure
1559
//
1560
TPM_RC
1561
ParseSessionBuffer(COMMAND* command  // IN: the structure that contains
6,308✔
1562
)
1563
{
1564
    TPM_RC     result;
6,308✔
1565
    UINT32     i;
6,308✔
1566
    INT32      size = 0;
6,308✔
1567
    TPM2B_AUTH extraKey;
6,308✔
1568
    UINT32     sessionIndex;
6,308✔
1569
    TPM_RC     errorIndex;
6,308✔
1570
    SESSION*   session = NULL;
6,308✔
1571
    //
1572
    // Check if a command allows any session in its session area.
1573
    if(!IsSessionAllowed(command->index))
6,308✔
1574
        return TPM_RC_AUTH_CONTEXT;
1575
    // Default-initialization.
1576
    command->sessionNum = 0;
6,308✔
1577

1578
    result              = RetrieveSessionData(command);
6,308✔
1579
    if(result != TPM_RC_SUCCESS)
6,308✔
1580
        return result;
1581
    // There is no command in the TPM spec that has more handles than
1582
    // MAX_SESSION_NUM.
1583
    pAssert(command->handleNum <= MAX_SESSION_NUM);
6,258✔
1584

1585
    // Associate the session with an authorization handle.
1586
    for(i = 0; i < command->handleNum; i++)
14,773✔
1587
    {
1588
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
8,515✔
1589
        {
1590
            // If the received session number is less than the number of handles
1591
            // that requires authorization, an error should be returned.
1592
            // Note: for all the TPM 2.0 commands, handles requiring
1593
            // authorization come first in a command input and there are only ever
1594
            // two values requiring authorization
1595
            if(command->sessionNum == 0)                // libtpms added begin (Coverity 1550499)
6,662✔
1596
                return TPM_RC_AUTH_MISSING;                // libtpms added end
1597
            if(i > (command->sessionNum - 1))
6,662✔
1598
                return TPM_RC_AUTH_MISSING;
1599
            // Record the handle associated with the authorization session
1600
            s_associatedHandles[i] = HierarchyNormalizeHandle(command->handles[i]);
6,662✔
1601
        }
1602
    }
1603
    // Consistency checks are done first to avoid authorization failure when the
1604
    // command will not be executed anyway.
1605
    for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++)
12,804✔
1606
    {
1607
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,767✔
1608
        // PW session must be an authorization session
1609
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,767✔
1610
        {
1611
            if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
5,688✔
1612
                return TPM_RCS_HANDLE + errorIndex;
12✔
1613
            // a password session can't be audit, encrypt or decrypt
1614
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
5,676✔
1615
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1616
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
5,676✔
UNCOV
1617
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1618
            session = NULL;
1619
        }
1620
        else
1621
        {
1622
            session = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1623

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

1629
            // See if the session is bound to a DA protected entity
1630
            // NOTE: Since a policy session is never bound, a policy is still
1631
            // usable even if the object is DA protected and the TPM is in
1632
            // lockout.
1633
            if(session->attributes.isDaBound == SET)
1,079✔
1634
            {
UNCOV
1635
                result = CheckLockedOut(session->attributes.isLockoutBound == SET);
×
UNCOV
1636
                if(result != TPM_RC_SUCCESS)
×
UNCOV
1637
                    return result;
×
1638
            }
1639
            // If this session is for auditing, make sure the cpHash is computed.
1640
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit))
1,079✔
1641
                ComputeCpHash(command, session->authHashAlg);
35✔
1642
        }
1643

1644
        // if the session has an associated handle, check the authorization
1645
        if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
6,755✔
1646
        {
1647
            result = CheckAuthSession(command, sessionIndex);
6,656✔
1648
            if(result != TPM_RC_SUCCESS)
6,656✔
1649
                return RcSafeAddToResult(result, errorIndex);
209✔
1650
        }
1651
        else
1652
        {
1653
            // a session that is not for authorization must either be encrypt,
1654
            // decrypt, or audit
1655
            if(!IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
99✔
1656
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1657
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
88✔
UNCOV
1658
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1659

1660
            // no authValue included in any of the HMAC computations
1661
            pAssert(session != NULL);
99✔
1662
            session->attributes.includeAuth = CLEAR;
99✔
1663

1664
            // check HMAC for encrypt/decrypt/audit only sessions
1665
            result = CheckSessionHMAC(command, sessionIndex);
99✔
1666
            if(result != TPM_RC_SUCCESS)
99✔
UNCOV
1667
                return RcSafeAddToResult(result, errorIndex);
×
1668
        }
1669
    }
1670
#if CC_GetCommandAuditDigest
1671
    // Check if the command should be audited. Need to do this before any parameter
1672
    // encryption so that the cpHash for the audit is correct
1673
    if(CommandAuditIsRequired(command->index))
6,037✔
1674
    {
1675
        result = CheckCommandAudit(command);
65✔
1676
        if(result != TPM_RC_SUCCESS)
65✔
1677
            return result;  // No session number to reference
1678
    }
1679
#endif
1680
    // Decrypt the first parameter if applicable. This should be the last operation
1681
    // in session processing.
1682
    // If the encrypt session is associated with a handle and the handle's
1683
    // authValue is available, then authValue is concatenated with sessionKey to
1684
    // generate encryption key, no matter if the handle is the session bound entity
1685
    // or not.
1686
    if(s_decryptSessionIndex != UNDEFINED_INDEX)
6,037✔
1687
    {
1688
        // If this is an authorization session, include the authValue in the
1689
        // generation of the decryption key
1690
        if(s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED)
160✔
1691
        {
1692
            EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], &extraKey);
110✔
1693
        }
1694
        else
1695
        {
1696
            extraKey.b.size = 0;
50✔
1697
        }
1698
        size   = DecryptSize(command->index);
160✔
1699
        result = CryptParameterDecryption(s_sessionHandles[s_decryptSessionIndex],
320✔
1700
                                          &s_nonceCaller[s_decryptSessionIndex].b,
160✔
1701
                                          command->parameterSize,
1702
                                          (UINT16)size,
1703
                                          &extraKey,
1704
                                          command->parameterBuffer);
1705
        if(result != TPM_RC_SUCCESS)
160✔
1706
            return RcSafeAddToResult(result,
2✔
1707
                                     TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
2✔
1708
    }
1709

1710
    return TPM_RC_SUCCESS;
1711
}
1712

1713
//*** CheckAuthNoSession()
1714
// Function to process a command with no session associated.
1715
// The function makes sure all the handles in the command require no authorization.
1716
//
1717
//  Return Type: TPM_RC
1718
//      TPM_RC_AUTH_MISSING         failure - one or more handles require
1719
//                                  authorization
1720
TPM_RC
1721
CheckAuthNoSession(COMMAND* command  // IN: command parsing structure
10,514✔
1722
)
1723
{
1724
    UINT32 i;
10,514✔
1725
#if CC_GetCommandAuditDigest
1726
    TPM_RC result = TPM_RC_SUCCESS;
10,514✔
1727
#endif
1728
    //
1729
    // Check if the command requires authorization
1730
    for(i = 0; i < command->handleNum; i++)
13,057✔
1731
    {
1732
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
2,567✔
1733
            return TPM_RC_AUTH_MISSING;
1734
    }
1735
#if CC_GetCommandAuditDigest
1736
    // Check if the command should be audited.
1737
    if(CommandAuditIsRequired(command->index))
10,490✔
1738
    {
UNCOV
1739
        result = CheckCommandAudit(command);
×
UNCOV
1740
        if(result != TPM_RC_SUCCESS)
×
1741
            return result;
1742
    }
1743
#endif
1744
    // Initialize number of sessions to be 0
1745
    command->sessionNum = 0;
10,490✔
1746

1747
    return TPM_RC_SUCCESS;
10,490✔
1748
}
1749

1750
//** Response Session Processing
1751
//*** Introduction
1752
//
1753
//  The following functions build the session area in a response and handle
1754
//  the audit sessions (if present).
1755
//
1756

1757
//*** ComputeRpHash()
1758
// Function to compute rpHash (Response Parameter Hash). The rpHash is only
1759
// computed if there is an HMAC authorization session and the return code is
1760
// TPM_RC_SUCCESS.
1761
static TPM2B_DIGEST* ComputeRpHash(
1,026✔
1762
    COMMAND*   command,  // IN: command structure
1763
    TPM_ALG_ID hashAlg   // IN: hash algorithm to compute rpHash
1764
)
1765
{
1766
    TPM2B_DIGEST* rpHash = GetRpHashPointer(command, hashAlg);
1,026✔
1767
    HASH_STATE    hashState;
1,026✔
1768
    //
1769
    if(rpHash->t.size == 0)
1,026✔
1770
    {
1771
        //   rpHash := hash(responseCode || commandCode || parameters)
1772

1773
        // Initiate hash creation.
1774
        rpHash->t.size = CryptHashStart(&hashState, hashAlg);
749✔
1775

1776
        // Add hash constituents.
1777
        CryptDigestUpdateInt(&hashState, sizeof(TPM_RC), TPM_RC_SUCCESS);
749✔
1778
        CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
749✔
1779
        CryptDigestUpdate(
749✔
1780
            &hashState, command->parameterSize, command->parameterBuffer);
749✔
1781
        // Complete hash computation.
1782
        CryptHashEnd2B(&hashState, &rpHash->b);
749✔
1783
    }
1784
    return rpHash;
1,026✔
1785
}
1786

1787
//*** InitAuditSession()
1788
// This function initializes the audit data in an audit session.
1789
static void InitAuditSession(SESSION* session  // session to be initialized
21✔
1790
)
1791
{
1792
    // Mark session as an audit session.
1793
    session->attributes.isAudit = SET;
21✔
1794

1795
    // Audit session can not be bound.
1796
    session->attributes.isBound = CLEAR;
21✔
1797

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

1801
    // Set the original digest value to be 0.
1802
    MemorySet(&session->u2.auditDigest.t.buffer, 0, session->u2.auditDigest.t.size);
21✔
1803
    return;
21✔
1804
}
1805

1806
//*** UpdateAuditDigest
1807
// Function to update an audit digest
1808
static void UpdateAuditDigest(
52✔
1809
    COMMAND* command, TPMI_ALG_HASH hashAlg, TPM2B_DIGEST* digest)
1810
{
1811
    HASH_STATE    hashState;
52✔
1812
    TPM2B_DIGEST* cpHash = GetCpHash(command, hashAlg);
52✔
1813
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, hashAlg);
52✔
1814
    //
1815
    pAssert(cpHash != NULL);
52✔
1816

1817
    // digestNew :=  hash (digestOld || cpHash || rpHash)
1818
    // Start hash computation.
1819
    digest->t.size = CryptHashStart(&hashState, hashAlg);
52✔
1820
    // Add old digest.
1821
    CryptDigestUpdate2B(&hashState, &digest->b);
52✔
1822
    // Add cpHash
1823
    CryptDigestUpdate2B(&hashState, &cpHash->b);
52✔
1824
    // Add rpHash
1825
    CryptDigestUpdate2B(&hashState, &rpHash->b);
52✔
1826
    // Finalize the hash.
1827
    CryptHashEnd2B(&hashState, &digest->b);
52✔
1828
}
52✔
1829

1830
//*** Audit()
1831
//This function updates the audit digest in an audit session.
1832
static void Audit(COMMAND* command,      // IN: primary control structure
35✔
1833
                  SESSION* auditSession  // IN: loaded audit session
1834
)
1835
{
1836
    UpdateAuditDigest(
35✔
1837
        command, auditSession->authHashAlg, &auditSession->u2.auditDigest);
35✔
1838
    return;
35✔
1839
}
1840

1841
#if CC_GetCommandAuditDigest
1842
//*** CommandAudit()
1843
// This function updates the command audit digest.
1844
static void CommandAudit(COMMAND* command  // IN:
17✔
1845
)
1846
{
1847
    // If the digest.size is one, it indicates the special case of changing
1848
    // the audit hash algorithm. For this case, no audit is done on exit.
1849
    // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1850
    // force an update to the NV on exit so that the change in digest will
1851
    // be recorded. So, it is safe to exit here without setting any flags
1852
    // because the digest change will be written to NV when this code exits.
1853
    if(gr.commandAuditDigest.t.size == 1)
17✔
1854
    {
UNCOV
1855
        gr.commandAuditDigest.t.size = 0;
×
UNCOV
1856
        return;
×
1857
    }
1858
    // If the digest size is zero, need to start a new digest and increment
1859
    // the audit counter.
1860
    if(gr.commandAuditDigest.t.size == 0)
17✔
1861
    {
1862
        gr.commandAuditDigest.t.size = CryptHashGetDigestSize(gp.auditHashAlg);
17✔
1863
        MemorySet(gr.commandAuditDigest.t.buffer, 0, gr.commandAuditDigest.t.size);
17✔
1864

1865
        // Bump the counter and save its value to NV.
1866
        gp.auditCounter++;
17✔
1867
        NV_SYNC_PERSISTENT(auditCounter);
17✔
1868
    }
1869
    UpdateAuditDigest(command, gp.auditHashAlg, &gr.commandAuditDigest);
17✔
1870
    return;
17✔
1871
}
1872
#endif
1873

1874
//*** UpdateAuditSessionStatus()
1875
// This function updates the internal audit related states of a session. It will:
1876
//  a) initialize the session as audit session and set it to be exclusive if this
1877
//     is the first time it is used for audit or audit reset was requested;
1878
//  b) report exclusive audit session;
1879
//  c) extend audit log; and
1880
//  d) clear exclusive audit session if no audit session found in the command.
1881
static void UpdateAuditSessionStatus(
14,595✔
1882
    COMMAND* command  // IN: primary control structure
1883
)
1884
{
1885
    UINT32     i;
14,595✔
1886
    TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
14,595✔
1887
    //
1888
    // Iterate through sessions
1889
    for(i = 0; i < command->sessionNum; i++)
20,279✔
1890
    {
1891
        SESSION* session;
5,684✔
1892
        //
1893
        // PW session do not have a loaded session and can not be an audit
1894
        // session either.  Skip it.
1895
        if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
1896
            continue;
4,706✔
1897
        session = SessionGet(s_sessionHandles[i]);
978✔
1898

1899
        // If a session is used for audit
1900
        if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit))
978✔
1901
        {
1902
            // An audit session has been found
1903
            auditSession = s_sessionHandles[i];
35✔
1904

1905
            // If the session has not been an audit session yet, or
1906
            // the auditSetting bits indicate a reset, initialize it and set
1907
            // it to be the exclusive session
1908
            if(session->attributes.isAudit == CLEAR
35✔
1909
               || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset))
14✔
1910
            {
1911
                InitAuditSession(session);
21✔
1912
                g_exclusiveAuditSession = auditSession;
21✔
1913
            }
1914
            else
1915
            {
1916
                // Check if the audit session is the current exclusive audit
1917
                // session and, if not, clear previous exclusive audit session.
1918
                if(g_exclusiveAuditSession != auditSession)
14✔
1919
                    g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
5✔
1920
            }
1921
            // Report audit session exclusivity.
1922
            if(g_exclusiveAuditSession == auditSession)
35✔
1923
            {
1924
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
30✔
1925
            }
1926
            else
1927
            {
1928
                CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
5✔
1929
            }
1930
            // Extend audit log.
1931
            Audit(command, session);
5,719✔
1932
        }
1933
    }
1934
    // If no audit session is found in the command, and the command allows
1935
    // a session then, clear the current exclusive
1936
    // audit session.
1937
    if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index))
14,595✔
1938
    {
1939
        g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
9,282✔
1940
    }
1941
    return;
14,595✔
1942
}
1943

1944
//*** ComputeResponseHMAC()
1945
// Function to compute HMAC for authorization session in a response.
1946
/*(See part 1 specification)
1947
// Function: Compute HMAC for response sessions
1948
//      The sessionAuth value
1949
//          authHMAC := HMACsHASH((sessionAuth | authValue),
1950
//                    (pHash | nonceTPM | nonceCaller | sessionAttributes))
1951
//  Where:
1952
//      HMACsHASH()     The HMAC algorithm using the hash algorithm specified when
1953
//                      the session was started.
1954
//
1955
//      sessionAuth     A TPMB_MEDIUM computed in a protocol-dependent way, using
1956
//                      KDFa. In an HMAC or KDF, only sessionAuth.buffer is used.
1957
//
1958
//      authValue       A TPM2B_AUTH that is found in the sensitive area of an
1959
//                      object. In an HMAC or KDF, only authValue.buffer is used
1960
//                      and all trailing zeros are removed.
1961
//
1962
//      pHash           Response parameters (rpHash) using the session hash. When
1963
//                      using a pHash in an HMAC computation, both the algorithm ID
1964
//                      and the digest are included.
1965
//
1966
//      nonceTPM        A TPM2B_NONCE that is generated by the entity using the
1967
//                      session. In an HMAC or KDF, only nonceTPM.buffer is used.
1968
//
1969
//      nonceCaller     a TPM2B_NONCE that was received the previous time the
1970
//                      session was used. In an HMAC or KDF, only
1971
//                      nonceCaller.buffer is used.
1972
//
1973
//      sessionAttributes   A TPMA_SESSION that indicates the attributes associated
1974
//                          with a particular use of the session.
1975
*/
1976
static void ComputeResponseHMAC(
974✔
1977
    COMMAND*      command,       // IN: command structure
1978
    UINT32        sessionIndex,  // IN: session index to be processed
1979
    SESSION*      session,       // IN: loaded session
1980
    TPM2B_DIGEST* hmac           // OUT: authHMAC
1981
)
1982
{
1983
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
974✔
1984
    TPM2B_KEY     key;  // HMAC key
974✔
1985
    BYTE          marshalBuffer[sizeof(TPMA_SESSION)];
974✔
1986
    BYTE*         buffer;
974✔
1987
    UINT32        marshalSize;
974✔
1988
    HMAC_STATE    hmacState;
974✔
1989
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, session->authHashAlg);
974✔
1990
    //
1991
    // Generate HMAC key
1992
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
974✔
1993

1994
    // Add the object authValue if required
1995
    if(session->attributes.includeAuth == SET)
974✔
1996
    {
1997
        // Note: includeAuth may be SET for a policy that is used in
1998
        // UndefineSpaceSpecial(). At this point, the Index has been deleted
1999
        // so the includeAuth will have no meaning. However, the
2000
        // s_associatedHandles[] value for the session is now set to TPM_RH_NULL so
2001
        // this will return the authValue associated with TPM_RH_NULL and that is
2002
        // and empty buffer.
2003
        TPM2B_AUTH authValue;
682✔
2004
        //
2005
        // Get the authValue with trailing zeros removed
2006
        EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
682✔
2007

2008
        // Add it to the key
2009
        MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
682✔
2010
    }
2011

2012
    // if the HMAC key size is 0, the response HMAC is computed according to the
2013
    // input HMAC
2014
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
974✔
2015
    {
2016
        hmac->t.size = 0;
127✔
2017
        return;
127✔
2018
    }
2019
    // Start HMAC computation.
2020
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
847✔
2021

2022
    // Add hash components.
2023
    CryptDigestUpdate2B(&hmacState.hashState, &rpHash->b);
847✔
2024
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
847✔
2025
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
847✔
2026

2027
    // Add session attributes.
2028
    buffer      = marshalBuffer;
847✔
2029
    marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL);
847✔
2030
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
847✔
2031

2032
    // Finalize HMAC.
2033
    CryptHmacEnd2B(&hmacState, &hmac->b);
847✔
2034

2035
    return;
847✔
2036
}
2037

2038
//*** UpdateInternalSession()
2039
// This function updates internal sessions by:
2040
// a) restarting session time; and
2041
// b) clearing a policy session since nonce is rolling.
2042
static void UpdateInternalSession(SESSION* session,  // IN: the session structure
978✔
2043
                                  UINT32   i         // IN: session number
2044
)
2045
{
2046
    // If nonce is rolling in a policy session, the policy related data
2047
    // will be re-initialized.
2048
    if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION
978✔
2049
       && IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
165✔
2050
    {
2051
        // When the nonce rolls it starts a new timing interval for the
2052
        // policy session.
2053
        SessionResetPolicyData(session);
121✔
2054
        SessionSetStartTime(session);
121✔
2055
    }
2056
    return;
978✔
2057
}
2058

2059
//*** BuildSingleResponseAuth()
2060
//   Function to compute response HMAC value for a policy or HMAC session.
2061
static TPM2B_NONCE* BuildSingleResponseAuth(
978✔
2062
    COMMAND*    command,       // IN: command structure
2063
    UINT32      sessionIndex,  // IN: session index to be processed
2064
    TPM2B_AUTH* auth           // OUT: authHMAC
2065
)
2066
{
2067
    // Fill in policy/HMAC based session response.
2068
    SESSION* session = SessionGet(s_sessionHandles[sessionIndex]);
978✔
2069
    //
2070
    // If the session is a policy session with isPasswordNeeded SET, the
2071
    // authorization field is empty.
2072
    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
978✔
2073
       && session->attributes.isPasswordNeeded == SET)
165✔
2074
        auth->t.size = 0;
4✔
2075
    else
2076
        // Compute response HMAC.
2077
        ComputeResponseHMAC(command, sessionIndex, session, auth);
974✔
2078

2079
    UpdateInternalSession(session, sessionIndex);
978✔
2080
    return &session->nonceTPM;
978✔
2081
}
2082

2083
//*** UpdateAllNonceTPM()
2084
// Updates TPM nonce for all sessions in command.
2085
static void UpdateAllNonceTPM(COMMAND* command  // IN: controlling structure
5,210✔
2086
)
2087
{
2088
    UINT32   i;
5,210✔
2089
    SESSION* session;
5,210✔
2090
    //
2091
    for(i = 0; i < command->sessionNum; i++)
10,894✔
2092
    {
2093
        // If not a PW session, compute the new nonceTPM.
2094
        if(s_sessionHandles[i] != TPM_RS_PW)
5,684✔
2095
        {
2096
            session = SessionGet(s_sessionHandles[i]);
978✔
2097
            // Update nonceTPM in both internal session and response.
2098
            CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
978✔
2099
        }
2100
    }
2101
    return;
5,210✔
2102
}
2103

2104
//*** BuildResponseSession()
2105
// Function to build Session buffer in a response. The authorization data is added
2106
// to the end of command->responseBuffer. The size of the authorization area is
2107
// accumulated in command->authSize.
2108
// When this is called, command->responseBuffer is pointing at the next location
2109
// in the response buffer to be filled. This is where the authorization sessions
2110
// will go, if any. command->parameterSize is the number of bytes that have been
2111
// marshaled as parameters in the output buffer.
2112
TPM_RC
2113
BuildResponseSession(COMMAND* command  // IN: structure that has relevant command
14,595✔
2114
                                       //     information
2115
)
2116
{
2117
    TPM_RC result = TPM_RC_SUCCESS;
14,595✔
2118

2119
    pAssert(command->authSize == 0);
14,595✔
2120

2121
    // Reset the parameter buffer to point to the start of the parameters so that
2122
    // there is a starting point for any rpHash that might be generated and so there
2123
    // is a place where parameter encryption would start
2124
    command->parameterBuffer = command->responseBuffer - command->parameterSize;
14,595✔
2125

2126
    // Session nonces should be updated before parameter encryption
2127
    if(command->tag == TPM_ST_SESSIONS)
14,595✔
2128
    {
2129
        UpdateAllNonceTPM(command);
5,210✔
2130

2131
        // Encrypt first parameter if applicable. Parameter encryption should
2132
        // happen after nonce update and before any rpHash is computed.
2133
        // If the encrypt session is associated with a handle, the authValue of
2134
        // this handle will be concatenated with sessionKey to generate
2135
        // encryption key, no matter if the handle is the session bound entity
2136
        // or not. The authValue is added to sessionKey only when the authValue
2137
        // is available.
2138
        if(s_encryptSessionIndex != UNDEFINED_INDEX)
5,210✔
2139
        {
2140
            UINT32     size;
152✔
2141
            TPM2B_AUTH extraKey;
152✔
2142
            //
2143
            extraKey.b.size = 0;
152✔
2144
            // If this is an authorization session, include the authValue in the
2145
            // generation of the encryption key
2146
            if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED)
152✔
2147
            {
2148
                EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
102✔
2149
                                   &extraKey);
2150
            }
2151
            size = EncryptSize(command->index);
152✔
2152
            // This function operates on internally-generated data that is
2153
            // expected to be well-formed for parameter encryption.
2154
            // In the event that there is a bug elsewhere in the code and the
2155
            // input data is not well-formed, CryptParameterEncryption will
2156
            // put the TPM into failure mode instead of allowing the out-of-
2157
            // band write.
2158
            CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
152✔
2159
                                     &s_nonceCaller[s_encryptSessionIndex].b,
152✔
2160
                                     command->parameterSize,
2161
                                     (UINT16)size,
2162
                                     &extraKey,
2163
                                     command->parameterBuffer);
2164
            if(g_inFailureMode)
152✔
2165
            {
UNCOV
2166
                result = TPM_RC_FAILURE;
×
UNCOV
2167
                goto Cleanup;
×
2168
            }
2169
        }
2170
    }
2171
    // Audit sessions should be processed regardless of the tag because
2172
    // a command with no session may cause a change of the exclusivity state.
2173
    UpdateAuditSessionStatus(command);
14,595✔
2174
#if CC_GetCommandAuditDigest
2175
    // Command Audit
2176
    if(CommandAuditIsRequired(command->index))
14,595✔
2177
        CommandAudit(command);
17✔
2178
#endif
2179
    // Process command with sessions.
2180
    if(command->tag == TPM_ST_SESSIONS)
14,595✔
2181
    {
2182
        UINT32 i;
5,210✔
2183
        //
2184
        pAssert(command->sessionNum > 0);
5,210✔
2185

2186
        // Iterate over each session in the command session area, and create
2187
        // corresponding sessions for response.
2188
        for(i = 0; i < command->sessionNum; i++)
10,894✔
2189
        {
2190
            TPM2B_NONCE* nonceTPM;
5,684✔
2191
            TPM2B_DIGEST responseAuth;
5,684✔
2192
            // Make sure that continueSession is SET on any Password session.
2193
            // This makes it marginally easier for the management software
2194
            // to keep track of the closed sessions.
2195
            if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
2196
            {
2197
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession);
4,706✔
2198
                responseAuth.t.size = 0;
4,706✔
2199
                nonceTPM            = (TPM2B_NONCE*)&responseAuth;
4,706✔
2200
            }
2201
            else
2202
            {
2203
                // Compute the response HMAC and get a pointer to the nonce used.
2204
                // This function will also update the values if needed. Note, the
2205
                nonceTPM = BuildSingleResponseAuth(command, i, &responseAuth);
978✔
2206
            }
2207
            command->authSize +=
11,368✔
2208
                TPM2B_NONCE_Marshal(nonceTPM, &command->responseBuffer, NULL);
5,684✔
2209
            command->authSize += TPMA_SESSION_Marshal(
5,684✔
2210
                &s_attributes[i], &command->responseBuffer, NULL);
2211
            command->authSize +=
11,368✔
2212
                TPM2B_DIGEST_Marshal(&responseAuth, &command->responseBuffer, NULL);
5,684✔
2213
            if(!IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
5,684✔
2214
                SessionFlush(s_sessionHandles[i]);
89✔
2215
        }
2216
    }
2217

2218
Cleanup:
14,595✔
2219
    return result;
14,595✔
2220
}
2221

2222
//*** SessionRemoveAssociationToHandle()
2223
// This function deals with the case where an entity associated with an authorization
2224
// is deleted during command processing. The primary use of this is to support
2225
// UndefineSpaceSpecial().
2226
void SessionRemoveAssociationToHandle(TPM_HANDLE handle)
2✔
2227
{
2228
    UINT32 i;
2✔
2229
    //
2230
    for(i = 0; i < MAX_SESSION_NUM; i++)
8✔
2231
    {
2232
        if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle))
6✔
2233
        {
2234
            s_associatedHandles[i] = TPM_RH_NULL;
2✔
2235
        }
2236
    }
2237
}
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