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

stefanberger / libtpms / #2036

05 Dec 2025 02:40PM UTC coverage: 77.213% (-0.01%) from 77.226%
#2036

push

travis-ci

web-flow
Merge fef9f3885 into 4f71e9b45

870 of 999 new or added lines in 77 files covered. (87.09%)

950 existing lines in 29 files now uncovered.

36283 of 46991 relevant lines covered (77.21%)

126719.67 hits per line

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

91.52
/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
        pAssert_RC(session);
11✔
97
        // If the session is bound to lockout, then use that as the relevant
98
        // handle. This means that an authorization failure with a bound session
99
        // bound to lockoutAuth will take precedence over any other
100
        // lockout check
101
        if(session->attributes.isLockoutBound == SET)
11✔
UNCOV
102
            handle = TPM_RH_LOCKOUT;
×
103
        if(session->attributes.isDaBound == CLEAR
11✔
104
           && (IsDAExempted(handle) || session->attributes.includeAuth == CLEAR))
11✔
105
            // If the handle was changed to TPM_RH_LOCKOUT, this will not return
106
            // TPM_RC_BAD_AUTH
107
            return TPM_RC_BAD_AUTH;
108
    }
109
    if(handle == TPM_RH_LOCKOUT)
20✔
110
    {
111
        pAssert_RC(gp.lockOutAuthEnabled == TRUE);
4✔
112

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

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

144
    return TPM_RC_AUTH_FAIL;
20✔
145
}
146

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

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

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

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

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

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

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

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

335
                nvAttributes = nvIndex->publicArea.attributes;
506✔
336

337
                if(IsWriteOperation(commandIndex))
506✔
338
                {
339
                    // AuthWrite can't be set for a PIN index
340
                    if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHWRITE))
224✔
341
                        result = TRUE;
220✔
342
                }
343
                else
344
                {
345
                    // A "read" operation
346
                    // For a PIN Index, the authValue is available as long as the
347
                    // Index has been written and the pinCount is less than pinLimit
348
                    if(IsNvPinFailIndex(nvAttributes)
282✔
349
                       || IsNvPinPassIndex(nvAttributes))
282✔
350
                    {
351
                        NV_PIN pin;
32✔
352
                        if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN))
32✔
353
                            break;  // return false
354

355
                        if(locator == (NV_REF)0)
31✔
356
                            break;  // return false
357

358
                        // get the index values
359
                        pin.intVal = NvGetUINT64Data(nvIndex, locator);
31✔
360
                        if(pin.pin.pinCount < pin.pin.pinLimit)
31✔
361
                            result = TRUE;
21✔
362
                    }
363
                    // For non-PIN Indexes, need to allow use of the authValue
364
                    else if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHREAD))
250✔
365
                        result = TRUE;
246✔
366
                }
367
            }
368
            break;
505✔
369
        case TPM_HT_PCR:
276✔
370
            // PCR handle.
371
            // authValue is always allowed for PCR
372
            result = TRUE;
276✔
373
            break;
276✔
374
        default:
375
            // Otherwise, authValue is not available
376
            break;
377
    }
378
    return result;
6,396✔
379
}
380

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

418
#  define ACT_GET_POLICY(N)                     \
419
      case TPM_RH_ACT_##N:                      \
420
          if(go.ACT_##N.authPolicy.t.size != 0) \
421
              result = TRUE;                    \
422
          break;
423

424
                    FOR_EACH_ACT(ACT_GET_POLICY)
425
#endif  // ACT_SUPPORT
426

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

492
//**  Session Parsing Functions
493

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

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

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

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

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

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

598
//*** GetCpHash()
599
// This function is used to access a precomputed cpHash.
600
static TPM2B_DIGEST* GetCpHash(COMMAND* command, TPMI_ALG_HASH hashAlg)
52✔
601
{
602
    TPM2B_DIGEST* cpHash = GetCpHashPointer(command, hashAlg);
52✔
603
    //
604
    pAssert_NULL(cpHash && cpHash->t.size != 0);
52✔
605
    return cpHash;
52✔
606
}
607

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

643
    // Advance the pointer
644
    pBuffer += size;
3✔
645

646
    // Get the size of what should be the template
647
    if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS)
3✔
648
        return FALSE;
649
    // See if this is reasonable
650
    if(size > pSize)
3✔
651
        return FALSE;
652
    // Hash the template data
653
    tHash.t.size = CryptHashBlock(
6✔
654
        session->authHashAlg, size, pBuffer, sizeof(tHash.t.buffer), tHash.t.buffer);
3✔
655
    return (MemoryEqual2B(&session->u1.templateHash.b, &tHash.b));
3✔
656
}
657

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

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

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

718
    // Compute secure channel key name hash
719
    // scKeyNameHash = hash(reqKeyName.size || reqKeyName.name || tpmKeyName.size || tpmKeyName.name)
720
    //  Start hash
721
    scKeyNameHash.t.size = CryptHashStart(&hashState, session->authHashAlg);
722

723
    //  Include reqKeyName if it needs to be checked, otherwise include Empty Buffer
724
    if(session->attributes.checkReqKey)
725
    {
726
        //  Add reqKeyName.size
727
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), reqKeyName->t.size);
728

729
        //  Add reqKeyName.name
730
        CryptDigestUpdate2B(&hashState, &reqKeyName->b);
731
    }
732
    else
733
    {
734
        //  Add zero size
735
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
736
    }
737

738
    //  Include tpmKeyName if it needs to be checked, otherwise include Empty Buffer
739
    if(session->attributes.checkTpmKey)
740
    {
741
        //  Add tpmKeyName.size
742
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), tpmKeyName->t.size);
743

744
        //  Add tpmKeyName.name
745
        CryptDigestUpdate2B(&hashState, &tpmKeyName->b);
746
    }
747
    else
748
    {
749
        //  Add zero size
750
        CryptDigestUpdateInt(&hashState, sizeof(UINT16), zeroSize);
751
    }
752

753
    //  Complete hash
754
    CryptHashEnd2B(&hashState, &scKeyNameHash.b);
755

756
    // and compare
757
    return MemoryEqual(session->scKeyNameHash.t.buffer,
758
                       scKeyNameHash.t.buffer,
759
                       scKeyNameHash.t.size);
760
}
761
#endif  // SEC_CHANNEL_SUPPORT
762

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

784
    // Get the authValue with trailing zeros removed
785
    EntityGetAuthValue(associatedHandle, &authValue);
5,607✔
786

787
    // Success if the values are identical.
788
    if(MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &authValue.b))
5,607✔
789
    {
790
        return TPM_RC_SUCCESS;
791
    }
792
    else  // if the digests are not identical
793
    {
794
        // Invoke DA protection if applicable.
795
        return IncrementLockout(sessionIndex);
79✔
796
    }
797
}
798

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

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

890
    // Continue with the HMAC processing.
891
    session = SessionGet(s_sessionHandles[sessionIndex]);
1,028✔
892
    pAssert_RC(session != NULL);
1,028✔
893

894
    // Generate HMAC key.
895
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1,028✔
896

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

922
    //  Add cpHash
923
    CryptDigestUpdate2B(&hmacState.hashState,
1,798✔
924
                        &ComputeCpHash(command, session->authHashAlg)->b);
899✔
925
    //  Add nonces as required
926
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
899✔
927
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
899✔
928
    if(nonceDecrypt != NULL)
899✔
929
        CryptDigestUpdate2B(&hmacState.hashState, &nonceDecrypt->b);
84✔
930
    if(nonceEncrypt != NULL)
899✔
931
        CryptDigestUpdate2B(&hmacState.hashState, &nonceEncrypt->b);
64✔
932
    //  Add sessionAttributes
933
    buffer      = marshalBuffer;
899✔
934
    marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), &buffer, NULL);
899✔
935
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
899✔
936
    // Complete the HMAC computation
937
    CryptHmacEnd2B(&hmacState, &hmac->b);
899✔
938

939
    return TPM_RC_SUCCESS;
899✔
940
}
941

942
//*** CheckSessionHMAC()
943
// This function checks the HMAC of in a session. It uses ComputeCommandHMAC()
944
// to compute the expected HMAC value and then compares the result with the
945
// HMAC in the authorization session. The authorization is successful if they
946
// are the same.
947
//
948
// If the authorizations are not the same, IncrementLockout() is called. It will
949
// return TPM_RC_AUTH_FAIL if the failure caused the failureCount to increment.
950
// Otherwise, it will return TPM_RC_BAD_AUTH.
951
//
952
//  Return Type: TPM_RC
953
//      TPM_RC_AUTH_FAIL        authorization failure caused failureCount increment
954
//      TPM_RC_BAD_AUTH         authorization failure did not cause failureCount
955
//                              increment
956
//
957
static TPM_RC CheckSessionHMAC(
1,028✔
958
    COMMAND* command,      // IN: primary control structure
959
    UINT32   sessionIndex  // IN: index of session to be processed
960
)
961
{
962
    TPM2B_DIGEST hmac;  // authHMAC for comparing
1,028✔
963
                        //
964
    // Compute authHMAC
965
    TPM_RC result = ComputeCommandHMAC(command, sessionIndex, &hmac);
1,028✔
966
    if(result != TPM_RC_SUCCESS)
1,028✔
967
        return result;
968

969
    // Compare the input HMAC with the authHMAC computed above.
970
    if(!MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &hmac.b))
1,028✔
971
    {
972
        // If an HMAC session has a failure, invoke the anti-hammering
973
        // if it applies to the authorized entity or the session.
974
        // Otherwise, just indicate that the authorization is bad.
975
        return IncrementLockout(sessionIndex);
10✔
976
    }
977
    return TPM_RC_SUCCESS;
978
}
979

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

1020
    // If the command is TPM2_PolicySecret(), make sure that
1021
    // either password or authValue is required
1022
    if(command->code == TPM_CC_PolicySecret
208✔
1023
       && session->attributes.isPasswordNeeded == CLEAR
UNCOV
1024
       && session->attributes.isAuthValueNeeded == CLEAR)
×
1025
        return TPM_RC_MODE;
1026
    // See if the PCR counter for the session is still valid.
1027
    if(!SessionPCRValueIsCurrent(session))
208✔
1028
        return TPM_RC_PCR_CHANGED;
1029
    // Get authPolicy.
1030
    policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], &authPolicy);
207✔
1031
    // Compare authPolicy.
1032
    if(!MemoryEqual2B(&session->u2.policyDigest.b, &authPolicy.b))
207✔
1033
        return TPM_RC_POLICY_FAIL;
1034
    // Policy is OK so check if the other factors are correct
1035

1036
    // Compare policy hash algorithm.
1037
    if(policyAlg != session->authHashAlg)
173✔
1038
        return TPM_RC_POLICY_FAIL;
1039

1040
    // Compare timeout.
1041
    if(session->timeout != 0)
173✔
1042
    {
1043
        // Cannot compare time if clock stop advancing.  An TPM_RC_NV_UNAVAILABLE
1044
        // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that
1045
        // a new nonce will be created just that, because TPM time can't advance
1046
        // we can't do time-based operations.
1047
        RETURN_IF_NV_IS_NOT_AVAILABLE;
11✔
1048

1049
        if((session->timeout < g_time) || (session->epoch != g_timeEpoch))
11✔
1050
            return TPM_RC_EXPIRED;
1051
    }
1052
    // If command code is provided it must match
1053
    if(session->commandCode != 0)
173✔
1054
    {
1055
        if(session->commandCode != command->code)
91✔
1056
            return TPM_RC_POLICY_CC;
1057
    }
1058
    else
1059
    {
1060
        // If command requires a DUP or ADMIN authorization, the session must have
1061
        // command code set.
1062
        AUTH_ROLE role = CommandAuthRole(command->index, sessionIndex);
82✔
1063
        if(role == AUTH_ADMIN || role == AUTH_DUP)
82✔
1064
            return TPM_RC_POLICY_FAIL;
1065
    }
1066
    // Check command locality.
1067
    {
1068
        BYTE  sessionLocality[sizeof(TPMA_LOCALITY)];
170✔
1069
        BYTE* buffer = sessionLocality;
170✔
1070

1071
        // Get existing locality setting in canonical form
1072
        sessionLocality[0] = 0;
170✔
1073
        TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
170✔
1074

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

1134
        // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
1135
        if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
4✔
1136
           != (session->attributes.nvWrittenState == SET))
4✔
1137
            return TPM_RC_POLICY_FAIL;
1138
    }
1139
#if SEC_CHANNEL_SUPPORT
1140
    if(session->attributes.checkSecureChannel)
1141
    {
1142
        TPM2B_NAME reqKeyName;
1143
        TPM2B_NAME tpmKeyName;
1144

1145
        // Check that the authorized TPM command is protected by an SPDM session and
1146
        // if so, get the names of the associated requester and TPM key
1147
        if(!IsSpdmSessionActive(&reqKeyName, &tpmKeyName))
1148
            return TPM_RC_CHANNEL;
1149

1150
        // If required, check the requester or TPM secure channel key name by comparing scKeyNameHash
1151
        if(session->attributes.checkReqKey == SET
1152
           || session->attributes.checkTpmKey == SET)
1153
        {
1154
            if(!CompareScKeyNameHash(session, &reqKeyName, &tpmKeyName))
1155
                return TPM_RC_CHANNEL_KEY;
1156
        }
1157
    }
1158
#endif  // SEC_CHANNEL_SUPPORT
1159
    return TPM_RC_SUCCESS;
1160
}
1161

1162
//*** RetrieveSessionData()
1163
// This function will unmarshal the sessions in the session area of a command. The
1164
// values are placed in the arrays that are defined at the beginning of this file.
1165
// The normal unmarshaling errors are possible.
1166
//
1167
//  Return Type: TPM_RC
1168
//      TPM_RC_SUCCSS       unmarshaled without error
1169
//      TPM_RC_SIZE         the number of bytes unmarshaled is not the same
1170
//                          as the value for authorizationSize in the command
1171
//
1172
static TPM_RC RetrieveSessionData(
6,308✔
1173
    COMMAND* command  // IN: main parsing structure for command
1174
)
1175
{
1176
    int          i;
6,308✔
1177
    TPM_RC       result;
6,308✔
1178
    SESSION*     session;
6,308✔
1179
    TPMA_SESSION sessionAttributes;
6,308✔
1180
    TPM_HT       sessionType;
6,308✔
1181
    INT32        sessionIndex;
6,308✔
1182
    TPM_RC       errorIndex;
6,308✔
1183
    //
1184
    s_decryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1185
    s_encryptSessionIndex = UNDEFINED_INDEX;
6,308✔
1186
    s_auditSessionIndex   = UNDEFINED_INDEX;
6,308✔
1187

1188
    for(sessionIndex = 0; command->authSize > 0; sessionIndex++)
13,105✔
1189
    {
1190
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,847✔
1191

1192
        // If maximum allowed number of sessions has been parsed, return a size
1193
        // error with a session number that is larger than the number of allowed
1194
        // sessions
1195
        if(sessionIndex == MAX_SESSION_NUM)
6,847✔
1196
            return TPM_RCS_SIZE + errorIndex;
4✔
1197
        // make sure that the associated handle for each session starts out
1198
        // unassigned
1199
        s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
6,843✔
1200

1201
        // First parameter: Session handle.
1202
        result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
6,843✔
1203
                                                &command->parameterBuffer,
1204
                                                &command->authSize,
1205
                                                TRUE);
1206
        if(result != TPM_RC_SUCCESS)
6,843✔
1207
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
16✔
1208
        // Second parameter: Nonce.
1209
        result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
6,827✔
1210
                                       &command->parameterBuffer,
1211
                                       &command->authSize);
1212
        if(result != TPM_RC_SUCCESS)
6,827✔
1213
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
8✔
1214
        // Third parameter: sessionAttributes.
1215
        result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
6,819✔
1216
                                        &command->parameterBuffer,
1217
                                        &command->authSize);
1218
        if(result != TPM_RC_SUCCESS)
6,819✔
1219
            return result + TPM_RC_S + g_rcIndex[sessionIndex];
4✔
1220
        // Fourth parameter: authValue (PW or HMAC).
1221
        result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
6,815✔
1222
                                      &command->parameterBuffer,
1223
                                      &command->authSize);
1224
        if(result != TPM_RC_SUCCESS)
6,815✔
1225
            return result + errorIndex;
4✔
1226

1227
        sessionAttributes = s_attributes[sessionIndex];
6,811✔
1228
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,811✔
1229
        {
1230
            // A PWAP session needs additional processing.
1231
            //     Can't have any attributes set other than continueSession bit
1232
            if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)
5,726✔
1233
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)
1234
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)
5,726✔
1235
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive)
1236
               || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset))
5,722✔
1237
                return TPM_RCS_ATTRIBUTES + errorIndex;
4✔
1238
            //     The nonce size must be zero.
1239
            if(s_nonceCaller[sessionIndex].t.size != 0)
5,722✔
1240
                return TPM_RCS_NONCE + errorIndex;
4✔
1241
            continue;
5,718✔
1242
        }
1243
        // For not password sessions...
1244
        // Find out if the session is loaded.
1245
        if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
1,085✔
1246
            return TPM_RC_REFERENCE_S0 + sessionIndex;
6✔
1247
        sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
1,079✔
1248
        session     = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1249
        pAssert_RC(session != NULL);
1,079✔
1250

1251
        // Check if the session is an HMAC/policy session.
1252
        if((session->attributes.isPolicy == SET && sessionType == TPM_HT_HMAC_SESSION)
1,079✔
1253
           || (session->attributes.isPolicy == CLEAR
1,079✔
1254
               && sessionType == TPM_HT_POLICY_SESSION))
871✔
UNCOV
1255
            return TPM_RCS_HANDLE + errorIndex;
×
1256
        // Check that this handle has not previously been used.
1257
        for(i = 0; i < sessionIndex; i++)
1,410✔
1258
        {
1259
            if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
331✔
UNCOV
1260
                return TPM_RCS_HANDLE + errorIndex;
×
1261
        }
1262
        // If the session is used for parameter encryption or audit as well, set
1263
        // the corresponding Indexes.
1264

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

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

1353
        // ... write the pending DA data and proceed.
UNCOV
1354
        NV_SYNC_PERSISTENT(lockOutAuthEnabled);
×
UNCOV
1355
        NV_SYNC_PERSISTENT(failedTries);
×
UNCOV
1356
        s_DAPendingOnNV = FALSE;
×
1357
    }
1358
    // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1359
    // is disabled...
1360
    if(lockoutAuthCheck)
158✔
1361
    {
1362
        if(gp.lockOutAuthEnabled == FALSE)
80✔
UNCOV
1363
            return TPM_RC_LOCKOUT;
×
1364
    }
1365
    else
1366
    {
1367
        // ... or if the number of failed tries has been maxed out.
1368
        if(gp.failedTries >= gp.maxTries)
78✔
1369
            return TPM_RC_LOCKOUT;
1370
#if USE_DA_USED
1371
        // If the daUsed flag is not SET, then no DA validation until the
1372
        // daUsed state is written to NV
1373
        if(!g_daUsed)
40✔
1374
        {
1375
            RETURN_IF_NV_IS_NOT_AVAILABLE;
10✔
1376
            g_daUsed        = TRUE;
10✔
1377
            gp.orderlyState = SU_DA_USED_VALUE;
10✔
1378
            NV_SYNC_PERSISTENT(orderlyState);
10✔
1379
            return TPM_RC_SUCCESS; // libtpms changed: was TPM_RC_RETRY;
10✔
1380
        }
1381
#endif
1382
    }
1383
    return TPM_RC_SUCCESS;
1384
}
1385

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

1421
    // Take care of physical presence
1422
    if(associatedHandle == TPM_RH_PLATFORM)
6,656✔
1423
    {
1424
        // If the physical presence is required for this command, check for PP
1425
        // assertion. If it isn't asserted, no point going any further.
1426
        if(PhysicalPresenceIsRequired(command->index)
1,023✔
1427
           && !_plat__PhysicalPresenceAsserted())
12✔
1428
            return TPM_RC_PP;
1429
    }
1430
    if(sessionHandle != TPM_RS_PW)
6,644✔
1431
    {
1432
        session = SessionGet(sessionHandle);
980✔
1433
        pAssert_RC(session != NULL);
980✔
1434

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

1545
#if CC_GetCommandAuditDigest
1546
//*** CheckCommandAudit()
1547
// This function is called before the command is processed if audit is enabled
1548
// for the command. It will check to see if the audit can be performed and
1549
// will ensure that the cpHash is available for the audit.
1550
//  Return Type: TPM_RC
1551
//      TPM_RC_NV_UNAVAILABLE       NV is not available for write
1552
//      TPM_RC_NV_RATE              NV is rate limiting
1553
static TPM_RC CheckCommandAudit(COMMAND* command)
65✔
1554
{
1555
    // If the audit digest is clear and command audit is required, NV must be
1556
    // available so that TPM2_GetCommandAuditDigest() is able to increment
1557
    // audit counter. If NV is not available, the function bails out to prevent
1558
    // the TPM from attempting an operation that would fail anyway.
1559
    if(gr.commandAuditDigest.t.size == 0
65✔
UNCOV
1560
       || GetCommandCode(command->index) == TPM_CC_GetCommandAuditDigest)
×
1561
    {
1562
        RETURN_IF_NV_IS_NOT_AVAILABLE;
65✔
1563
    }
1564
    // Make sure that the cpHash is computed for the algorithm
1565
    ComputeCpHash(command, gp.auditHashAlg);
65✔
1566
    return TPM_RC_SUCCESS;
65✔
1567
}
1568
#endif
1569

1570
//*** ParseSessionBuffer()
1571
// This function is the entry function for command session processing.
1572
// It iterates sessions in session area and reports if the required authorization
1573
// has been properly provided. It also processes audit session and passes the
1574
// information of encryption sessions to parameter encryption module.
1575
//
1576
//  Return Type: TPM_RC
1577
//        various           parsing failure or authorization failure
1578
//
1579
TPM_RC
1580
ParseSessionBuffer(COMMAND* command  // IN: the structure that contains
6,308✔
1581
)
1582
{
1583
    TPM_RC     result;
6,308✔
1584
    UINT32     i;
6,308✔
1585
    INT32      size = 0;
6,308✔
1586
    TPM2B_AUTH extraKey;
6,308✔
1587
    UINT32     sessionIndex;
6,308✔
1588
    TPM_RC     errorIndex;
6,308✔
1589
    SESSION*   session = NULL;
6,308✔
1590
    //
1591
    // Check if a command allows any session in its session area.
1592
    if(!IsSessionAllowed(command->index))
6,308✔
1593
        return TPM_RC_AUTH_CONTEXT;
1594
    // Default-initialization.
1595
    command->sessionNum = 0;
6,308✔
1596

1597
    result              = RetrieveSessionData(command);
6,308✔
1598
    if(result != TPM_RC_SUCCESS)
6,308✔
1599
        return result;
1600
    // There is no command in the TPM spec that has more handles than
1601
    // MAX_SESSION_NUM.
1602
    pAssert_RC(command->handleNum <= MAX_SESSION_NUM);
6,258✔
1603

1604
    // Associate the session with an authorization handle.
1605
    for(i = 0; i < command->handleNum; i++)
14,773✔
1606
    {
1607
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
8,515✔
1608
        {
1609
            // If the received session number is less than the number of handles
1610
            // that requires authorization, an error should be returned.
1611
            // Note: for all the TPM 2.0 commands, handles requiring
1612
            // authorization come first in a command input and there are only ever
1613
            // two values requiring authorization
1614
            if(command->sessionNum == 0)                // libtpms added begin (Coverity 1550499)
6,662✔
1615
                return TPM_RC_AUTH_MISSING;                // libtpms added end
1616
            if(i > (command->sessionNum - 1))
6,662✔
1617
                return TPM_RC_AUTH_MISSING;
1618
            // Record the handle associated with the authorization session
1619
            s_associatedHandles[i] = HierarchyNormalizeHandle(command->handles[i]);
6,662✔
1620
        }
1621
    }
1622
    // Consistency checks are done first to avoid authorization failure when the
1623
    // command will not be executed anyway.
1624
    for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++)
12,804✔
1625
    {
1626
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,767✔
1627
        // PW session must be an authorization session
1628
        if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
6,767✔
1629
        {
1630
            if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
5,688✔
1631
                return TPM_RCS_HANDLE + errorIndex;
12✔
1632
            // a password session can't be audit, encrypt or decrypt
1633
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
5,676✔
1634
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1635
               || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
5,676✔
UNCOV
1636
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1637
            session = NULL;
1638
        }
1639
        else
1640
        {
1641
            session = SessionGet(s_sessionHandles[sessionIndex]);
1,079✔
1642
            pAssert_RC(session != NULL);
1,079✔
1643

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

1649
            // See if the session is bound to a DA protected entity
1650
            // NOTE: Since a policy session is never bound, a policy is still
1651
            // usable even if the object is DA protected and the TPM is in
1652
            // lockout.
1653
            if(session->attributes.isDaBound == SET)
1,079✔
1654
            {
UNCOV
1655
                result = CheckLockedOut(session->attributes.isLockoutBound == SET);
×
UNCOV
1656
                if(result != TPM_RC_SUCCESS)
×
UNCOV
1657
                    return result;
×
1658
            }
1659
            // If this session is for auditing, make sure the cpHash is computed.
1660
            if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit))
1,079✔
1661
                ComputeCpHash(command, session->authHashAlg);
35✔
1662
        }
1663

1664
        // if the session has an associated handle, check the authorization
1665
        if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
6,755✔
1666
        {
1667
            result = CheckAuthSession(command, sessionIndex);
6,656✔
1668
            if(result != TPM_RC_SUCCESS)
6,656✔
1669
                return RcSafeAddToResult(result, errorIndex);
209✔
1670
        }
1671
        else
1672
        {
1673
            // a session that is not for authorization must either be encrypt,
1674
            // decrypt, or audit
1675
            if(!IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)
99✔
1676
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt)
1677
               && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt))
88✔
UNCOV
1678
                return TPM_RCS_ATTRIBUTES + errorIndex;
×
1679

1680
            // no authValue included in any of the HMAC computations
1681
            pAssert_RC(session != NULL);
99✔
1682
            session->attributes.includeAuth = CLEAR;
99✔
1683

1684
            // check HMAC for encrypt/decrypt/audit only sessions
1685
            result = CheckSessionHMAC(command, sessionIndex);
99✔
1686
            if(result != TPM_RC_SUCCESS)
99✔
UNCOV
1687
                return RcSafeAddToResult(result, errorIndex);
×
1688
        }
1689
    }
1690
#if CC_GetCommandAuditDigest
1691
    // Check if the command should be audited. Need to do this before any parameter
1692
    // encryption so that the cpHash for the audit is correct
1693
    if(CommandAuditIsRequired(command->index))
6,037✔
1694
    {
1695
        result = CheckCommandAudit(command);
65✔
1696
        if(result != TPM_RC_SUCCESS)
65✔
1697
            return result;  // No session number to reference
1698
    }
1699
#endif
1700
    // Decrypt the first parameter if applicable. This should be the last operation
1701
    // in session processing.
1702
    // If the encrypt session is associated with a handle and the handle's
1703
    // authValue is available, then authValue is concatenated with sessionKey to
1704
    // generate encryption key, no matter if the handle is the session bound entity
1705
    // or not.
1706
    if(s_decryptSessionIndex != UNDEFINED_INDEX)
6,037✔
1707
    {
1708
        // If this is an authorization session, include the authValue in the
1709
        // generation of the decryption key
1710
        if(s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED)
160✔
1711
        {
1712
            EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], &extraKey);
110✔
1713
        }
1714
        else
1715
        {
1716
            extraKey.b.size = 0;
50✔
1717
        }
1718
        size = DecryptSize(command->index);
160✔
1719
        pAssert_RC(command->parameterSize <= INT32_MAX);
160✔
1720
        result = CryptParameterDecryption(s_sessionHandles[s_decryptSessionIndex],
320✔
1721
                                          &s_nonceCaller[s_decryptSessionIndex].b,
160✔
1722
                                          command->parameterSize,
1723
                                          (UINT16)size,
1724
                                          &extraKey,
1725
                                          command->parameterBuffer);
1726
        if(result != TPM_RC_SUCCESS)
160✔
1727
            return RcSafeAddToResult(result,
2✔
1728
                                     TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
2✔
1729
    }
1730

1731
    return TPM_RC_SUCCESS;
1732
}
1733

1734
//*** CheckAuthNoSession()
1735
// Function to process a command with no session associated.
1736
// The function makes sure all the handles in the command require no authorization.
1737
//
1738
//  Return Type: TPM_RC
1739
//      TPM_RC_AUTH_MISSING         failure - one or more handles require
1740
//                                  authorization
1741
TPM_RC
1742
CheckAuthNoSession(COMMAND* command  // IN: command parsing structure
10,513✔
1743
)
1744
{
1745
    UINT32 i;
10,513✔
1746
#if CC_GetCommandAuditDigest
1747
    TPM_RC result = TPM_RC_SUCCESS;
10,513✔
1748
#endif
1749
    //
1750
    // Check if the command requires authorization
1751
    for(i = 0; i < command->handleNum; i++)
13,056✔
1752
    {
1753
        if(CommandAuthRole(command->index, i) != AUTH_NONE)
2,567✔
1754
            return TPM_RC_AUTH_MISSING;
1755
    }
1756
#if CC_GetCommandAuditDigest
1757
    // Check if the command should be audited.
1758
    if(CommandAuditIsRequired(command->index))
10,489✔
1759
    {
UNCOV
1760
        result = CheckCommandAudit(command);
×
UNCOV
1761
        if(result != TPM_RC_SUCCESS)
×
1762
            return result;
1763
    }
1764
#endif
1765
    // Initialize number of sessions to be 0
1766
    command->sessionNum = 0;
10,489✔
1767

1768
    return TPM_RC_SUCCESS;
10,489✔
1769
}
1770

1771
//** Response Session Processing
1772
//*** Introduction
1773
//
1774
//  The following functions build the session area in a response and handle
1775
//  the audit sessions (if present).
1776
//
1777

1778
//*** ComputeRpHash()
1779
// Function to compute rpHash (Response Parameter Hash). The rpHash is only
1780
// computed if there is an HMAC authorization session and the return code is
1781
// TPM_RC_SUCCESS.
1782
static TPM2B_DIGEST* ComputeRpHash(
1,026✔
1783
    COMMAND*   command,  // IN: command structure
1784
    TPM_ALG_ID hashAlg   // IN: hash algorithm to compute rpHash
1785
)
1786
{
1787
    TPM2B_DIGEST* rpHash = GetRpHashPointer(command, hashAlg);
1,026✔
1788
    HASH_STATE    hashState;
1,026✔
1789
    //
1790
    if(rpHash->t.size == 0)
1,026✔
1791
    {
1792
        //   rpHash := hash(responseCode || commandCode || parameters)
1793

1794
        // Initiate hash creation.
1795
        rpHash->t.size = CryptHashStart(&hashState, hashAlg);
749✔
1796

1797
        // Add hash constituents.
1798
        CryptDigestUpdateInt(&hashState, sizeof(TPM_RC), TPM_RC_SUCCESS);
749✔
1799
        CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code);
749✔
1800
        CryptDigestUpdate(
749✔
1801
            &hashState, command->parameterSize, command->parameterBuffer);
749✔
1802
        // Complete hash computation.
1803
        CryptHashEnd2B(&hashState, &rpHash->b);
749✔
1804
    }
1805
    return rpHash;
1,026✔
1806
}
1807

1808
//*** InitAuditSession()
1809
// This function initializes the audit data in an audit session.
1810
static void InitAuditSession(SESSION* session  // session to be initialized
21✔
1811
)
1812
{
1813
    // Mark session as an audit session.
1814
    session->attributes.isAudit = SET;
21✔
1815

1816
    // Audit session can not be bound.
1817
    session->attributes.isBound = CLEAR;
21✔
1818

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

1822
    // Set the original digest value to be 0.
1823
    MemorySet(&session->u2.auditDigest.t.buffer, 0, session->u2.auditDigest.t.size);
21✔
1824
    return;
21✔
1825
}
1826

1827
//*** UpdateAuditDigest
1828
// Function to update an audit digest
1829
static void UpdateAuditDigest(
52✔
1830
    COMMAND* command, TPMI_ALG_HASH hashAlg, TPM2B_DIGEST* digest)
1831
{
1832
    HASH_STATE    hashState;
52✔
1833
    TPM2B_DIGEST* cpHash = GetCpHash(command, hashAlg);
52✔
1834
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, hashAlg);
52✔
1835
    //
1836
    pAssert_VOID_OK(cpHash != NULL);
52✔
1837

1838
    // digestNew :=  hash (digestOld || cpHash || rpHash)
1839
    // Start hash computation.
1840
    digest->t.size = CryptHashStart(&hashState, hashAlg);
52✔
1841
    // Add old digest.
1842
    CryptDigestUpdate2B(&hashState, &digest->b);
52✔
1843
    // Add cpHash
1844
    CryptDigestUpdate2B(&hashState, &cpHash->b);
52✔
1845
    // Add rpHash
1846
    CryptDigestUpdate2B(&hashState, &rpHash->b);
52✔
1847
    // Finalize the hash.
1848
    CryptHashEnd2B(&hashState, &digest->b);
52✔
1849
}
52✔
1850

1851
//*** Audit()
1852
//This function updates the audit digest in an audit session.
1853
static void Audit(COMMAND* command,      // IN: primary control structure
35✔
1854
                  SESSION* auditSession  // IN: loaded audit session
1855
)
1856
{
1857
    UpdateAuditDigest(
35✔
1858
        command, auditSession->authHashAlg, &auditSession->u2.auditDigest);
35✔
1859
    return;
35✔
1860
}
1861

1862
#if CC_GetCommandAuditDigest
1863
//*** CommandAudit()
1864
// This function updates the command audit digest.
1865
static void CommandAudit(COMMAND* command  // IN:
17✔
1866
)
1867
{
1868
    // If the digest.size is one, it indicates the special case of changing
1869
    // the audit hash algorithm. For this case, no audit is done on exit.
1870
    // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1871
    // force an update to the NV on exit so that the change in digest will
1872
    // be recorded. So, it is safe to exit here without setting any flags
1873
    // because the digest change will be written to NV when this code exits.
1874
    if(gr.commandAuditDigest.t.size == 1)
17✔
1875
    {
UNCOV
1876
        gr.commandAuditDigest.t.size = 0;
×
UNCOV
1877
        return;
×
1878
    }
1879
    // If the digest size is zero, need to start a new digest and increment
1880
    // the audit counter.
1881
    if(gr.commandAuditDigest.t.size == 0)
17✔
1882
    {
1883
        gr.commandAuditDigest.t.size = CryptHashGetDigestSize(gp.auditHashAlg);
17✔
1884
        MemorySet(gr.commandAuditDigest.t.buffer, 0, gr.commandAuditDigest.t.size);
17✔
1885

1886
        // Bump the counter and save its value to NV.
1887
        gp.auditCounter++;
17✔
1888
        NV_SYNC_PERSISTENT(auditCounter);
17✔
1889
    }
1890
    UpdateAuditDigest(command, gp.auditHashAlg, &gr.commandAuditDigest);
17✔
1891
    return;
17✔
1892
}
1893
#endif
1894

1895
//*** UpdateAuditSessionStatus()
1896
// This function updates the internal audit related states of a session. It will:
1897
//  a) initialize the session as audit session and set it to be exclusive if this
1898
//     is the first time it is used for audit or audit reset was requested;
1899
//  b) report exclusive audit session;
1900
//  c) extend audit log; and
1901
//  d) clear exclusive audit session if no audit session found in the command.
1902
static void UpdateAuditSessionStatus(
14,594✔
1903
    COMMAND* command  // IN: primary control structure
1904
)
1905
{
1906
    UINT32     i;
14,594✔
1907
    TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
14,594✔
1908
    //
1909
    // Iterate through sessions
1910
    for(i = 0; i < command->sessionNum; i++)
20,278✔
1911
    {
1912
        SESSION* session;
5,684✔
1913
        //
1914
        // PW session do not have a loaded session and can not be an audit
1915
        // session either.  Skip it.
1916
        if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
1917
            continue;
4,706✔
1918
        session = SessionGet(s_sessionHandles[i]);
978✔
1919
        pAssert_VOID_OK(session != NULL);
978✔
1920

1921
        // If a session is used for audit
1922
        if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit))
978✔
1923
        {
1924
            // An audit session has been found
1925
            auditSession = s_sessionHandles[i];
35✔
1926

1927
            // If the session has not been an audit session yet, or
1928
            // the auditSetting bits indicate a reset, initialize it and set
1929
            // it to be the exclusive session
1930
            if(session->attributes.isAudit == CLEAR
35✔
1931
               || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset))
14✔
1932
            {
1933
                InitAuditSession(session);
21✔
1934
                g_exclusiveAuditSession = auditSession;
21✔
1935
            }
1936
            else
1937
            {
1938
                // Check if the audit session is the current exclusive audit
1939
                // session and, if not, clear previous exclusive audit session.
1940
                if(g_exclusiveAuditSession != auditSession)
14✔
1941
                    g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
5✔
1942
            }
1943
            // Report audit session exclusivity.
1944
            if(g_exclusiveAuditSession == auditSession)
35✔
1945
            {
1946
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
30✔
1947
            }
1948
            else
1949
            {
1950
                CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive);
5✔
1951
            }
1952
            // Extend audit log.
1953
            Audit(command, session);
5,719✔
1954
        }
1955
    }
1956
    // If no audit session is found in the command, and the command allows
1957
    // a session then, clear the current exclusive
1958
    // audit session.
1959
    if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index))
14,594✔
1960
    {
1961
        g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
9,281✔
1962
    }
1963
    return;
14,594✔
1964
}
1965

1966
//*** ComputeResponseHMAC()
1967
// Function to compute HMAC for authorization session in a response.
1968
/*(See part 1 specification)
1969
// Function: Compute HMAC for response sessions
1970
//      The sessionAuth value
1971
//          authHMAC := HMACsHASH((sessionAuth | authValue),
1972
//                    (pHash | nonceTPM | nonceCaller | sessionAttributes))
1973
//  Where:
1974
//      HMACsHASH()     The HMAC algorithm using the hash algorithm specified when
1975
//                      the session was started.
1976
//
1977
//      sessionAuth     A TPMB_MEDIUM computed in a protocol-dependent way, using
1978
//                      KDFa. In an HMAC or KDF, only sessionAuth.buffer is used.
1979
//
1980
//      authValue       A TPM2B_AUTH that is found in the sensitive area of an
1981
//                      object. In an HMAC or KDF, only authValue.buffer is used
1982
//                      and all trailing zeros are removed.
1983
//
1984
//      pHash           Response parameters (rpHash) using the session hash. When
1985
//                      using a pHash in an HMAC computation, both the algorithm ID
1986
//                      and the digest are included.
1987
//
1988
//      nonceTPM        A TPM2B_NONCE that is generated by the entity using the
1989
//                      session. In an HMAC or KDF, only nonceTPM.buffer is used.
1990
//
1991
//      nonceCaller     a TPM2B_NONCE that was received the previous time the
1992
//                      session was used. In an HMAC or KDF, only
1993
//                      nonceCaller.buffer is used.
1994
//
1995
//      sessionAttributes   A TPMA_SESSION that indicates the attributes associated
1996
//                          with a particular use of the session.
1997
*/
1998
static void ComputeResponseHMAC(
974✔
1999
    COMMAND*      command,       // IN: command structure
2000
    UINT32        sessionIndex,  // IN: session index to be processed
2001
    SESSION*      session,       // IN: loaded session
2002
    TPM2B_DIGEST* hmac           // OUT: authHMAC
2003
)
2004
{
2005
    TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
974✔
2006
    TPM2B_KEY     key;  // HMAC key
974✔
2007
    BYTE          marshalBuffer[sizeof(TPMA_SESSION)];
974✔
2008
    BYTE*         buffer;
974✔
2009
    UINT32        marshalSize;
974✔
2010
    HMAC_STATE    hmacState;
974✔
2011
    TPM2B_DIGEST* rpHash = ComputeRpHash(command, session->authHashAlg);
974✔
2012
    //
2013
    // Generate HMAC key
2014
    MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
974✔
2015

2016
    // Add the object authValue if required
2017
    if(session->attributes.includeAuth == SET)
974✔
2018
    {
2019
        // Note: includeAuth may be SET for a policy that is used in
2020
        // UndefineSpaceSpecial(). At this point, the Index has been deleted
2021
        // so the includeAuth will have no meaning. However, the
2022
        // s_associatedHandles[] value for the session is now set to TPM_RH_NULL so
2023
        // this will return the authValue associated with TPM_RH_NULL and that is
2024
        // and empty buffer.
2025
        TPM2B_AUTH authValue;
682✔
2026
        //
2027
        // Get the authValue with trailing zeros removed
2028
        EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue);
682✔
2029

2030
        // Add it to the key
2031
        MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer));
682✔
2032
    }
2033

2034
    // if the HMAC key size is 0, the response HMAC is computed according to the
2035
    // input HMAC
2036
    if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0)
974✔
2037
    {
2038
        hmac->t.size = 0;
127✔
2039
        return;
127✔
2040
    }
2041
    // Start HMAC computation.
2042
    hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b);
847✔
2043

2044
    // Add hash components.
2045
    CryptDigestUpdate2B(&hmacState.hashState, &rpHash->b);
847✔
2046
    CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b);
847✔
2047
    CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b);
847✔
2048

2049
    // Add session attributes.
2050
    buffer      = marshalBuffer;
847✔
2051
    marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL);
847✔
2052
    CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer);
847✔
2053

2054
    // Finalize HMAC.
2055
    CryptHmacEnd2B(&hmacState, &hmac->b);
847✔
2056

2057
    return;
847✔
2058
}
2059

2060
//*** UpdateInternalSession()
2061
// This function updates internal sessions by:
2062
// a) restarting session time; and
2063
// b) clearing a policy session since nonce is rolling.
2064
static void UpdateInternalSession(SESSION* session,  // IN: the session structure
978✔
2065
                                  UINT32   i         // IN: session number
2066
)
2067
{
2068
    // If nonce is rolling in a policy session, the policy related data
2069
    // will be re-initialized.
2070
    if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION
978✔
2071
       && IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
165✔
2072
    {
2073
        // When the nonce rolls it starts a new timing interval for the
2074
        // policy session.
2075
        SessionResetPolicyData(session);
121✔
2076
        SessionSetStartTime(session);
121✔
2077
    }
2078
    return;
978✔
2079
}
2080

2081
//*** BuildSingleResponseAuth()
2082
//   Function to compute response HMAC value for a policy or HMAC session.
2083
static TPM2B_NONCE* BuildSingleResponseAuth(
978✔
2084
    COMMAND*    command,       // IN: command structure
2085
    UINT32      sessionIndex,  // IN: session index to be processed
2086
    TPM2B_AUTH* auth           // OUT: authHMAC
2087
)
2088
{
2089
    // Fill in policy/HMAC based session response.
2090
    SESSION* session = SessionGet(s_sessionHandles[sessionIndex]);
978✔
2091
    pAssert_NULL(session != NULL);
978✔
2092

2093
    // If the session is a policy session with isPasswordNeeded SET, the
2094
    // authorization field is empty.
2095
    if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
978✔
2096
       && session->attributes.isPasswordNeeded == SET)
165✔
2097
        auth->t.size = 0;
4✔
2098
    else
2099
        // Compute response HMAC.
2100
        ComputeResponseHMAC(command, sessionIndex, session, auth);
974✔
2101

2102
    UpdateInternalSession(session, sessionIndex);
978✔
2103
    return &session->nonceTPM;
978✔
2104
}
2105

2106
//*** UpdateAllNonceTPM()
2107
// Updates TPM nonce for all sessions in command.
2108
static void UpdateAllNonceTPM(COMMAND* command  // IN: controlling structure
5,210✔
2109
)
2110
{
2111
    UINT32   i;
5,210✔
2112
    SESSION* session;
5,210✔
2113
    //
2114
    for(i = 0; i < command->sessionNum; i++)
10,894✔
2115
    {
2116
        // If not a PW session, compute the new nonceTPM.
2117
        if(s_sessionHandles[i] != TPM_RS_PW)
5,684✔
2118
        {
2119
            session = SessionGet(s_sessionHandles[i]);
978✔
2120
            pAssert_VOID_OK(session != NULL);
978✔
2121
            // Update nonceTPM in both internal session and response.
2122
            CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
978✔
2123
        }
2124
    }
2125
    return;
5,210✔
2126
}
2127

2128
//*** BuildResponseSession()
2129
// Function to build Session buffer in a response. The authorization data is added
2130
// to the end of command->responseBuffer. The size of the authorization area is
2131
// accumulated in command->authSize.
2132
// When this is called, command->responseBuffer is pointing at the next location
2133
// in the response buffer to be filled. This is where the authorization sessions
2134
// will go, if any. command->parameterSize is the number of bytes that have been
2135
// marshaled as parameters in the output buffer.
2136
TPM_RC
2137
BuildResponseSession(COMMAND* command  // IN: structure that has relevant command
14,594✔
2138
                                       //     information
2139
)
2140
{
2141
    TPM_RC result = TPM_RC_SUCCESS;
14,594✔
2142

2143
    pAssert_RC(command->authSize == 0);
14,594✔
2144

2145
    // Reset the parameter buffer to point to the start of the parameters so that
2146
    // there is a starting point for any rpHash that might be generated and so there
2147
    // is a place where parameter encryption would start
2148
    command->parameterBuffer = command->responseBuffer - command->parameterSize;
14,594✔
2149

2150
    // Session nonces should be updated before parameter encryption
2151
    if(command->tag == TPM_ST_SESSIONS)
14,594✔
2152
    {
2153
        UpdateAllNonceTPM(command);
5,210✔
2154
        VERIFY_NOT_FAILED();
5,210✔
2155

2156
        // Encrypt first parameter if applicable. Parameter encryption should
2157
        // happen after nonce update and before any rpHash is computed.
2158
        // If the encrypt session is associated with a handle, the authValue of
2159
        // this handle will be concatenated with sessionKey to generate
2160
        // encryption key, no matter if the handle is the session bound entity
2161
        // or not. The authValue is added to sessionKey only when the authValue
2162
        // is available.
2163
        if(s_encryptSessionIndex != UNDEFINED_INDEX)
5,210✔
2164
        {
2165
            UINT32     size;
152✔
2166
            TPM2B_AUTH extraKey;
152✔
2167
            //
2168
            extraKey.b.size = 0;
152✔
2169
            // If this is an authorization session, include the authValue in the
2170
            // generation of the encryption key
2171
            if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED)
152✔
2172
            {
2173
                EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
102✔
2174
                                   &extraKey);
2175
            }
2176
            size = EncryptSize(command->index);
152✔
2177
            pAssert_RC(command->parameterSize <= INT32_MAX);
152✔
2178
            // This function operates on internally-generated data that is
2179
            // expected to be well-formed for parameter encryption.
2180
            // In the event that there is a bug elsewhere in the code and the
2181
            // input data is not well-formed, CryptParameterEncryption will
2182
            // put the TPM into failure mode instead of allowing the out-of-
2183
            // band write.
2184
            CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
152✔
2185
                                     &s_nonceCaller[s_encryptSessionIndex].b,
152✔
2186
                                     command->parameterSize,
2187
                                     (UINT16)size,
2188
                                     &extraKey,
2189
                                     command->parameterBuffer);
2190
            if(_plat__InFailureMode())
152✔
2191
            {
UNCOV
2192
                result = TPM_RC_FAILURE;
×
UNCOV
2193
                goto Cleanup;
×
2194
            }
2195
        }
2196
    }
2197
    // Audit sessions should be processed regardless of the tag because
2198
    // a command with no session may cause a change of the exclusivity state.
2199
    UpdateAuditSessionStatus(command);
14,594✔
2200
    VERIFY_NOT_FAILED();
14,594✔
2201
#if CC_GetCommandAuditDigest
2202
    // Command Audit
2203
    if(CommandAuditIsRequired(command->index))
14,594✔
2204
        CommandAudit(command);
17✔
2205
#endif
2206
    // Process command with sessions.
2207
    if(command->tag == TPM_ST_SESSIONS)
14,594✔
2208
    {
2209
        UINT32 i;
5,210✔
2210
        //
2211
        pAssert_RC(command->sessionNum > 0);
5,210✔
2212

2213
        // Iterate over each session in the command session area, and create
2214
        // corresponding sessions for response.
2215
        for(i = 0; i < command->sessionNum; i++)
10,894✔
2216
        {
2217
            TPM2B_NONCE* nonceTPM;
5,684✔
2218
            TPM2B_DIGEST responseAuth;
5,684✔
2219
            // Make sure that continueSession is SET on any Password session.
2220
            // This makes it marginally easier for the management software
2221
            // to keep track of the closed sessions.
2222
            if(s_sessionHandles[i] == TPM_RS_PW)
5,684✔
2223
            {
2224
                SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession);
4,706✔
2225
                responseAuth.t.size = 0;
4,706✔
2226
                nonceTPM            = (TPM2B_NONCE*)&responseAuth;
4,706✔
2227
            }
2228
            else
2229
            {
2230
                // Compute the response HMAC and get a pointer to the nonce used.
2231
                // This function will also update the values if needed. Note, the
2232
                nonceTPM = BuildSingleResponseAuth(command, i, &responseAuth);
978✔
2233
                pAssert_RC(nonceTPM != NULL);
978✔
2234
            }
2235
            command->authSize +=
11,368✔
2236
                TPM2B_NONCE_Marshal(nonceTPM, &command->responseBuffer, NULL);
5,684✔
2237
            command->authSize += TPMA_SESSION_Marshal(
5,684✔
2238
                &s_attributes[i], &command->responseBuffer, NULL);
2239
            command->authSize +=
11,368✔
2240
                TPM2B_DIGEST_Marshal(&responseAuth, &command->responseBuffer, NULL);
5,684✔
2241
            if(!IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession))
5,684✔
2242
            {
2243
                SessionFlush(s_sessionHandles[i]);
89✔
2244
                VERIFY_NOT_FAILED();
5,684✔
2245
            }
2246
        }
2247
    }
2248

2249
Cleanup:
14,594✔
2250
    return result;
2251
}
2252

2253
//*** SessionRemoveAssociationToHandle()
2254
// This function deals with the case where an entity associated with an authorization
2255
// is deleted during command processing. The primary use of this is to support
2256
// UndefineSpaceSpecial().
2257
void SessionRemoveAssociationToHandle(TPM_HANDLE handle)
2✔
2258
{
2259
    UINT32 i;
2✔
2260
    //
2261
    for(i = 0; i < MAX_SESSION_NUM; i++)
8✔
2262
    {
2263
        if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle))
6✔
2264
        {
2265
            s_associatedHandles[i] = TPM_RH_NULL;
2✔
2266
        }
2267
    }
2268
}
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