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

stefanberger / libtpms / #2022

23 Sep 2025 01:11PM UTC coverage: 77.227% (+0.009%) from 77.218%
#2022

push

travis-ci

web-flow
Merge a45c293de into 4504f47c6

36116 of 46766 relevant lines covered (77.23%)

125180.04 hits per line

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

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

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

67
//**  Includes and Data Definitions
68

69
#define SESSION_PROCESS_C
70

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

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

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

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

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

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

198
    return TPM_RC_AUTH_FAIL;
20✔
199
}
200

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

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

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

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

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

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

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

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

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

388
                nvAttributes = nvIndex->publicArea.attributes;
506✔
389

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

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

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

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

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

540
//**  Session Parsing Functions
541

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

924
    return hmac;
899✔
925
}
926

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

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

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

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

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

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

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

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

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

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

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

1148
    for(sessionIndex = 0; command->authSize > 0; sessionIndex++)
13,105✔
1149
    {
1150
        errorIndex = TPM_RC_S + g_rcIndex[sessionIndex];
6,847✔
1151

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1683
    return TPM_RC_SUCCESS;
1684
}
1685

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

1720
    return TPM_RC_SUCCESS;
10,489✔
1721
}
1722

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2008
    return;
847✔
2009
}
2010

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

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

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

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

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

2092
    pAssert(command->authSize == 0);
14,594✔
2093

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

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

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

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

2191
Cleanup:
14,594✔
2192
    return result;
14,594✔
2193
}
2194

2195
//*** SessionRemoveAssociationToHandle()
2196
// This function deals with the case where an entity associated with an authorization
2197
// is deleted during command processing. The primary use of this is to support
2198
// UndefineSpaceSpecial().
2199
void SessionRemoveAssociationToHandle(TPM_HANDLE handle)
2✔
2200
{
2201
    UINT32 i;
2✔
2202
    //
2203
    for(i = 0; i < MAX_SESSION_NUM; i++)
8✔
2204
    {
2205
        if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle))
6✔
2206
        {
2207
            s_associatedHandles[i] = TPM_RH_NULL;
2✔
2208
        }
2209
    }
2210
}
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