blob: ffdbe75c7f67cfa74714bf7693dc791f597a8c46 [file] [log] [blame]
Vadim Bendebury56797522015-05-20 10:32:25 -07001// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#define SESSION_PROCESS_C
9#include "InternalRoutines.h"
10#include "SessionProcess_fp.h"
11#include "Platform.h"
12//
13//
14// Authorization Support Functions
15//
16// IsDAExempted()
17//
18// This function indicates if a handle is exempted from DA logic. A handle is exempted if it is
19// a) a primary seed handle,
20// b) an object with noDA bit SET,
21// c) an NV Index with TPMA_NV_NO_DA bit SET, or
22// d) a PCR handle.
23//
24// Return Value Meaning
25//
26// TRUE handle is exempted from DA logic
27// FALSE handle is not exempted from DA logic
28//
29BOOL
30IsDAExempted(
31 TPM_HANDLE handle // IN: entity handle
32 )
33{
34 BOOL result = FALSE;
35 switch(HandleGetType(handle))
36 {
37 case TPM_HT_PERMANENT:
38 // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from
39 // DA protection.
40 result = (handle != TPM_RH_LOCKOUT);
41 break;
42 // When this function is called, a persistent object will have been loaded
43 // into an object slot and assigned a transient handle.
44 case TPM_HT_TRANSIENT:
45 {
46 OBJECT *object;
47 object = ObjectGet(handle);
48 result = (object->publicArea.objectAttributes.noDA == SET);
49 break;
50 }
51 case TPM_HT_NV_INDEX:
52 {
53 NV_INDEX nvIndex;
54 NvGetIndexInfo(handle, &nvIndex);
55 result = (nvIndex.publicArea.attributes.TPMA_NV_NO_DA == SET);
56 break;
57 }
58 case TPM_HT_PCR:
59 // PCRs are always exempted from DA.
60 result = TRUE;
61 break;
62 default:
63 break;
64 }
65 return result;
66}
67//
68//
69// IncrementLockout()
70//
71// This function is called after an authorization failure that involves use of an authValue. If the entity
72// referenced by the handle is not exempt from DA protection, then the failedTries counter will be
73// incremented.
74//
75// Error Returns Meaning
76//
77// TPM_RC_AUTH_FAIL authorization failure that caused DA lockout to increment
78// TPM_RC_BAD_AUTH authorization failure did not cause DA lockout to increment
79//
80static TPM_RC
81IncrementLockout(
82 UINT32 sessionIndex
83 )
84{
85 TPM_HANDLE handle = s_associatedHandles[sessionIndex];
86 TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
87 TPM_RC result;
88 SESSION *session = NULL;
89 // Don't increment lockout unless the handle associated with the session
90 // is DA protected or the session is bound to a DA protected entity.
91 if(sessionHandle == TPM_RS_PW)
92 {
93 if(IsDAExempted(handle))
94 return TPM_RC_BAD_AUTH;
95 }
96 else
97 {
98 session = SessionGet(sessionHandle);
99 // If the session is bound to lockout, then use that as the relevant
100 // handle. This means that an auth failure with a bound session
101 // bound to lockoutAuth will take precedence over any other
102 // lockout check
103 if(session->attributes.isLockoutBound == SET)
104 handle = TPM_RH_LOCKOUT;
105 if( session->attributes.isDaBound == CLEAR
106 && IsDAExempted(handle)
107 )
108 // If the handle was changed to TPM_RH_LOCKOUT, this will not return
109 // TPM_RC_BAD_AUTH
110 return TPM_RC_BAD_AUTH;
111 }
112 if(handle == TPM_RH_LOCKOUT)
113 {
114 pAssert(gp.lockOutAuthEnabled);
115 gp.lockOutAuthEnabled = FALSE;
116 // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since
117 // the lockout auth will be reset at startup.
118 if(gp.lockoutRecovery != 0)
119 {
120 result = NvIsAvailable();
121 if(result != TPM_RC_SUCCESS)
122 {
123 // No NV access for now. Put the TPM in pending mode.
124 s_DAPendingOnNV = TRUE;
125 }
126 else
127 {
128 // Update NV.
129 NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled);
130 g_updateNV = TRUE;
131 }
132 }
133 }
134 else
135 {
136 if(gp.recoveryTime != 0)
137 {
138 gp.failedTries++;
139 result = NvIsAvailable();
140 if(result != TPM_RC_SUCCESS)
141 {
142 // No NV access for now. Put the TPM in pending mode.
143 s_DAPendingOnNV = TRUE;
144 }
145 else
146 {
147 // Record changes to NV.
148 NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
149 g_updateNV = TRUE;
150 }
151 }
152 }
153 // Register a DA failure and reset the timers.
154 DARegisterFailure(handle);
155 return TPM_RC_AUTH_FAIL;
156}
157//
158//
159// IsSessionBindEntity()
160//
161// This function indicates if the entity associated with the handle is the entity, to which this session is bound.
162// The binding would occur by making the bind parameter in TPM2_StartAuthSession() not equal to
163// TPM_RH_NULL. The binding only occurs if the session is an HMAC session. The bind value is a
164// combination of the Name and the authValue of the entity.
165//
166// Return Value Meaning
167//
168// TRUE handle points to the session start entity
169// FALSE handle does not point to the session start entity
170//
171static BOOL
172IsSessionBindEntity(
173 TPM_HANDLE associatedHandle, // IN: handle to be authorized
174 SESSION *session // IN: associated session
175 )
176{
177 TPM2B_NAME entity; // The bind value for the entity
178 // If the session is not bound, return FALSE.
179 if(!session->attributes.isBound)
180 return FALSE;
181 // Compute the bind value for the entity.
182 SessionComputeBoundEntity(associatedHandle, &entity);
183 // Compare to the bind value in the session.
184 session->attributes.requestWasBound =
185 Memory2BEqual(&entity.b, &session->u1.boundEntity.b);
186 return session->attributes.requestWasBound;
187}
188//
189//
190// IsPolicySessionRequired()
191//
192// Checks if a policy session is required for a command. If a command requires DUP or ADMIN role
193// authorization, then the handle that requires that role is the first handle in the command. This simplifies
194// this checking. If a new command is created that requires multiple ADMIN role authorizations, then it will
195// have to be special-cased in this function. A policy session is required if:
196// a) the command requires the DUP role,
197// b) the command requires the ADMIN role and the authorized entity is an object and its adminWithPolicy
198// bit is SET, or
199// c) the command requires the ADMIN role and the authorized entity is a permanent handle or an NV
200// Index.
201// d) The authorized entity is a PCR belonging to a policy group, and has its policy initialized
202//
203// Return Value Meaning
204//
205// TRUE policy session is required
206// FALSE policy session is not required
207//
208static BOOL
209IsPolicySessionRequired(
210 TPM_CC commandCode, // IN: command code
211 UINT32 sessionIndex // IN: session index
212 )
213{
214 AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex);
215 TPM_HT type = HandleGetType(s_associatedHandles[sessionIndex]);
216 if(role == AUTH_DUP)
217 return TRUE;
218 if(role == AUTH_ADMIN)
219 {
220 if(type == TPM_HT_TRANSIENT)
221 {
222 OBJECT *object = ObjectGet(s_associatedHandles[sessionIndex]);
223 if(object->publicArea.objectAttributes.adminWithPolicy == CLEAR)
224 return FALSE;
225 }
226 return TRUE;
227 }
228//
229 if(type == TPM_HT_PCR)
230 {
231 if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex]))
232 {
233 TPM2B_DIGEST policy;
234 TPMI_ALG_HASH policyAlg;
235 policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex],
236 &policy);
237 if(policyAlg != TPM_ALG_NULL)
238 return TRUE;
239 }
240 }
241 return FALSE;
242}
243//
244//
245// IsAuthValueAvailable()
246//
247// This function indicates if authValue is available and allowed for USER role authorization of an entity.
248// This function is similar to IsAuthPolicyAvailable() except that it does not check the size of the authValue
249// as IsAuthPolicyAvailable() does (a null authValue is a valid auth, but a null policy is not a valid policy).
250// This function does not check that the handle reference is valid or if the entity is in an enabled hierarchy.
251// Those checks are assumed to have been performed during the handle unmarshaling.
252//
253// Return Value Meaning
254//
255// TRUE authValue is available
256// FALSE authValue is not available
257//
258static BOOL
259IsAuthValueAvailable(
260 TPM_HANDLE handle, // IN: handle of entity
261 TPM_CC commandCode, // IN: commandCode
262 UINT32 sessionIndex // IN: session index
263 )
264{
265 BOOL result = FALSE;
266 // If a policy session is required, the entity can not be authorized by
267 // authValue. However, at this point, the policy session requirement should
268 // already have been checked.
269 pAssert(!IsPolicySessionRequired(commandCode, sessionIndex));
270 switch(HandleGetType(handle))
271 {
272 case TPM_HT_PERMANENT:
273 switch(handle)
274 {
275 // At this point hierarchy availability has already been
276 // checked so primary seed handles are always available here
277 case TPM_RH_OWNER:
278 case TPM_RH_ENDORSEMENT:
279 case TPM_RH_PLATFORM:
280#ifdef VENDOR_PERMANENT
281 // This vendor defined handle associated with the
282 // manufacturer's shared secret
283 case VENDOR_PERMANENT:
284#endif
285 // NullAuth is always available.
286 case TPM_RH_NULL:
287 // At the point when authValue availability is checked, control
288 // path has already passed the DA check so LockOut auth is
289 // always available here
290 case TPM_RH_LOCKOUT:
291 result = TRUE;
292 break;
293 default:
294 // Otherwise authValue is not available.
295 break;
296 }
297 break;
298 case TPM_HT_TRANSIENT:
299 // A persistent object has already been loaded and the internal
300 // handle changed.
301 {
302 OBJECT *object;
303 object = ObjectGet(handle);
304 // authValue is always available for a sequence object.
305 if(ObjectIsSequence(object))
306 {
307 result = TRUE;
308 break;
309 }
310 // authValue is available for an object if it has its sensitive
311 // portion loaded and
312 // 1. userWithAuth bit is SET, or
313 // 2. ADMIN role is required
314 if( object->attributes.publicOnly == CLEAR
315 && (object->publicArea.objectAttributes.userWithAuth == SET
316 || (CommandAuthRole(commandCode, sessionIndex) == AUTH_ADMIN
317 && object->publicArea.objectAttributes.adminWithPolicy
318 == CLEAR)))
319 result = TRUE;
320 }
321 break;
322 case TPM_HT_NV_INDEX:
323 // NV Index.
324 {
325 NV_INDEX nvIndex;
326 NvGetIndexInfo(handle, &nvIndex);
327 if(IsWriteOperation(commandCode))
328 {
329 if (nvIndex.publicArea.attributes.TPMA_NV_AUTHWRITE == SET)
330 result = TRUE;
331 }
332 else
333 {
334 if (nvIndex.publicArea.attributes.TPMA_NV_AUTHREAD == SET)
335 result = TRUE;
336 }
337 }
338 break;
339 case TPM_HT_PCR:
340 // PCR handle.
341 // authValue is always allowed for PCR
342 result = TRUE;
343 break;
344 default:
345 // Otherwise, authValue is not available
346 break;
347 }
348 return result;
349}
350//
351//
352//
353// IsAuthPolicyAvailable()
354//
355// This function indicates if an authPolicy is available and allowed.
356// This function does not check that the handle reference is valid or if the entity is in an enabled hierarchy.
357// Those checks are assumed to have been performed during the handle unmarshaling.
358//
359// Return Value Meaning
360//
361// TRUE authPolicy is available
362// FALSE authPolicy is not available
363//
364static BOOL
365IsAuthPolicyAvailable(
366 TPM_HANDLE handle, // IN: handle of entity
367 TPM_CC commandCode, // IN: commandCode
368 UINT32 sessionIndex // IN: session index
369 )
370{
371 BOOL result = FALSE;
372 switch(HandleGetType(handle))
373 {
374 case TPM_HT_PERMANENT:
375 switch(handle)
376 {
377 // At this point hierarchy availability has already been checked.
378 case TPM_RH_OWNER:
379 if (gp.ownerPolicy.t.size != 0)
380 result = TRUE;
381 break;
382 case TPM_RH_ENDORSEMENT:
383 if (gp.endorsementPolicy.t.size != 0)
384 result = TRUE;
385 break;
386 case TPM_RH_PLATFORM:
387 if (gc.platformPolicy.t.size != 0)
388 result = TRUE;
389 break;
390 case TPM_RH_LOCKOUT:
391 if(gp.lockoutPolicy.t.size != 0)
392 result = TRUE;
393 break;
394 default:
395 break;
396 }
397 break;
398 case TPM_HT_TRANSIENT:
399 {
400 // Object handle.
401 // An evict object would already have been loaded and given a
402 // transient object handle by this point.
403 OBJECT *object = ObjectGet(handle);
404 // Policy authorization is not available for an object with only
405 // public portion loaded.
406 if(object->attributes.publicOnly == CLEAR)
407 {
408 // Policy authorization is always available for an object but
409 // is never available for a sequence.
410 if(!ObjectIsSequence(object))
411 result = TRUE;
412 }
413 break;
414 }
415 case TPM_HT_NV_INDEX:
416 // An NV Index.
417 {
418 NV_INDEX nvIndex;
419 NvGetIndexInfo(handle, &nvIndex);
420 // If the policy size is not zero, check if policy can be used.
421 if(nvIndex.publicArea.authPolicy.t.size != 0)
422 {
423 // If policy session is required for this handle, always
424 // uses policy regardless of the attributes bit setting
425 if(IsPolicySessionRequired(commandCode, sessionIndex))
426 result = TRUE;
427 // Otherwise, the presence of the policy depends on the NV
428 // attributes.
429 else if(IsWriteOperation(commandCode))
430 {
431 if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYWRITE
432 == SET)
433 result = TRUE;
434 }
435 else
436 {
437 if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYREAD
438 == SET)
439 result = TRUE;
440 }
441 }
442 }
443 break;
444 case TPM_HT_PCR:
445 // PCR handle.
446 if(PCRPolicyIsAvailable(handle))
447 result = TRUE;
448 break;
449 default:
450 break;
451 }
452 return result;
453}
454//
455//
456// Session Parsing Functions
457//
458// ComputeCpHash()
459//
460// This function computes the cpHash as defined in Part 2 and described in Part 1.
461//
462static void
463ComputeCpHash(
464 TPMI_ALG_HASH hashAlg, // IN: hash algorithm
465 TPM_CC commandCode, // IN: command code
466 UINT32 handleNum, // IN: number of handle
467 TPM_HANDLE handles[], // IN: array of handle
468 UINT32 parmBufferSize, // IN: size of input parameter area
469 BYTE *parmBuffer, // IN: input parameter area
470 TPM2B_DIGEST *cpHash, // OUT: cpHash
471 TPM2B_DIGEST *nameHash // OUT: name hash of command
472 )
473{
474 UINT32 i;
475 HASH_STATE hashState;
476 TPM2B_NAME name;
477//
478 // cpHash = hash(commandCode [ || authName1
479 // [ || authName2
480 // [ || authName 3 ]]]
481 // [ || parameters])
482 // A cpHash can contain just a commandCode only if the lone session is
483 // an audit session.
484 // Start cpHash.
485 cpHash->t.size = CryptStartHash(hashAlg, &hashState);
486 // Add commandCode.
487 CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
488 // Add authNames for each of the handles.
489 for(i = 0; i < handleNum; i++)
490 {
Vadim Bendebury3d5312a2015-06-01 18:19:06 -0700491 name.t.size = EntityGetName(handles[i], &name.t.buffer);
Vadim Bendebury56797522015-05-20 10:32:25 -0700492 CryptUpdateDigest2B(&hashState, &name.b);
493 }
494 // Add the parameters.
495 CryptUpdateDigest(&hashState, parmBufferSize, parmBuffer);
496 // Complete the hash.
497 CryptCompleteHash2B(&hashState, &cpHash->b);
498 // If the nameHash is needed, compute it here.
499 if(nameHash != NULL)
500 {
501 // Start name hash. hashState may be reused.
502 nameHash->t.size = CryptStartHash(hashAlg, &hashState);
503 // Adding names.
504 for(i = 0; i < handleNum; i++)
505 {
Vadim Bendebury3d5312a2015-06-01 18:19:06 -0700506 name.t.size = EntityGetName(handles[i], &name.t.buffer);
Vadim Bendebury56797522015-05-20 10:32:25 -0700507 CryptUpdateDigest2B(&hashState, &name.b);
508 }
509 // Complete hash.
510 CryptCompleteHash2B(&hashState, &nameHash->b);
511 }
512 return;
513}
514//
515//
516// CheckPWAuthSession()
517//
518// This function validates the authorization provided in a PWAP session. It compares the input value to
519// authValue of the authorized entity. Argument sessionIndex is used to get handles handle of the
520// referenced entities from s_inputAuthValues[] and s_associatedHandles[].
521//
522// Error Returns Meaning
523//
524// TPM_RC_AUTH_FAIL auth fails and increments DA failure count
525// TPM_RC_BAD_AUTH auth fails but DA does not apply
526//
527static TPM_RC
528CheckPWAuthSession(
529 UINT32 sessionIndex // IN: index of session to be processed
530 )
531{
532 TPM2B_AUTH authValue;
533 TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex];
534 // Strip trailing zeros from the password.
535 MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]);
536 // Get the auth value and size.
537 authValue.t.size = EntityGetAuthValue(associatedHandle, &authValue.t.buffer);
538 // Success if the digests are identical.
539 if(Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &authValue.b))
540 {
541 return TPM_RC_SUCCESS;
542 }
543 else // if the digests are not identical
544 {
545 // Invoke DA protection if applicable.
546 return IncrementLockout(sessionIndex);
547 }
548}
549//
550//
551// ComputeCommandHMAC()
552//
553// This function computes the HMAC for an authorization session in a command.
554//
555static void
556ComputeCommandHMAC(
557 UINT32 sessionIndex, // IN: index of session to be processed
558 TPM2B_DIGEST *cpHash, // IN: cpHash
559 TPM2B_DIGEST *hmac // OUT: authorization HMAC
560 )
561{
562 TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
563 TPM2B_KEY key;
564 BYTE marshalBuffer[sizeof(TPMA_SESSION)];
565 BYTE *buffer;
566 UINT32 marshalSize;
567 HMAC_STATE hmacState;
568 TPM2B_NONCE *nonceDecrypt;
569 TPM2B_NONCE *nonceEncrypt;
570 SESSION *session;
571 TPM_HT sessionHandleType =
572 HandleGetType(s_sessionHandles[sessionIndex]);
573 nonceDecrypt = NULL;
574 nonceEncrypt = NULL;
575 // Determine if extra nonceTPM values are going to be required.
576 // If this is the first session (sessionIndex = 0) and it is an authorization
577 // session that uses an HMAC, then check if additional session nonces are to be
578 // included.
579 if( sessionIndex == 0
580 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
581 {
582 // If there is a decrypt session and if this is not the decrypt session,
583 // then an extra nonce may be needed.
584 if( s_decryptSessionIndex != UNDEFINED_INDEX
585 && s_decryptSessionIndex != sessionIndex)
586 {
587 // Will add the nonce for the decrypt session.
588 SESSION *decryptSession
589 = SessionGet(s_sessionHandles[s_decryptSessionIndex]);
590 nonceDecrypt = &decryptSession->nonceTPM;
591 }
592 // Now repeat for the encrypt session.
593 if( s_encryptSessionIndex != UNDEFINED_INDEX
594 && s_encryptSessionIndex != sessionIndex
595//
596 && s_encryptSessionIndex != s_decryptSessionIndex)
597 {
598 // Have to have the nonce for the encrypt session.
599 SESSION *encryptSession
600 = SessionGet(s_sessionHandles[s_encryptSessionIndex]);
601 nonceEncrypt = &encryptSession->nonceTPM;
602 }
603 }
604 // Continue with the HMAC processing.
605 session = SessionGet(s_sessionHandles[sessionIndex]);
606 // Generate HMAC key.
607 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
608 // Check if the session has an associated handle and if the associated entity
609 // is the one to which the session is bound. If not, add the authValue of
610 // this entity to the HMAC key.
611 // If the session is bound to the object or the session is a policy session
612 // with no authValue required, do not include the authValue in the HMAC key.
613 // Note: For a policy session, its isBound attribute is CLEARED.
614 // If the session isn't used for authorization, then there is no auth value
615 // to add
616 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
617 {
618 // used for auth so see if this is a policy session with authValue needed
619 // or an hmac session that is not bound
Vadim Bendebury3d5312a2015-06-01 18:19:06 -0700620 if (((sessionHandleType == TPM_HT_POLICY_SESSION)
621 && (session->attributes.isAuthValueNeeded == SET))
622 || ((sessionHandleType == TPM_HT_HMAC_SESSION)
623 && !IsSessionBindEntity(s_associatedHandles[sessionIndex], session))
Vadim Bendebury56797522015-05-20 10:32:25 -0700624 )
625 {
626 // add the authValue to the HMAC key
627 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
628 key.t.size = key.t.size
629 + EntityGetAuthValue(s_associatedHandles[sessionIndex],
630 (AUTH_VALUE *)&(key.t.buffer[key.t.size]));
631 }
632 }
633 // if the HMAC key size is 0, a NULL string HMAC is allowed
634 if( key.t.size == 0
635 && s_inputAuthValues[sessionIndex].t.size == 0)
636 {
637 hmac->t.size = 0;
638 return;
639 }
640 // Start HMAC
641 hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
642 // Add cpHash
643 CryptUpdateDigest2B(&hmacState, &cpHash->b);
644 // Add nonceCaller
645 CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
646 // Add nonceTPM
647 CryptUpdateDigest2B(&hmacState, &session->nonceTPM.b);
648 // If needed, add nonceTPM for decrypt session
649 if(nonceDecrypt != NULL)
650 CryptUpdateDigest2B(&hmacState, &nonceDecrypt->b);
651 // If needed, add nonceTPM for encrypt session
652 if(nonceEncrypt != NULL)
653 CryptUpdateDigest2B(&hmacState, &nonceEncrypt->b);
654 // Add sessionAttributes
655 buffer = marshalBuffer;
656 marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]),
657 &buffer, NULL);
658 CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
659 // Complete the HMAC computation
660 CryptCompleteHMAC2B(&hmacState, &hmac->b);
661 return;
662}
663//
664//
665// CheckSessionHMAC()
666//
667// This function checks the HMAC of in a session. It uses ComputeCommandHMAC() to compute the
668// expected HMAC value and then compares the result with the HMAC in the authorization session. The
669// authorization is successful if they are the same.
670// If the authorizations are not the same, IncrementLockout() is called. It will return TPM_RC_AUTH_FAIL if
671// the failure caused the failureCount to increment. Otherwise, it will return TPM_RC_BAD_AUTH.
672//
673// Error Returns Meaning
674//
675// TPM_RC_AUTH_FAIL auth failure caused failureCount increment
676// TPM_RC_BAD_AUTH auth failure did not cause failureCount increment
677//
678static TPM_RC
679CheckSessionHMAC(
680 UINT32 sessionIndex, // IN: index of session to be processed
681 TPM2B_DIGEST *cpHash // IN: cpHash of the command
682 )
683{
684 TPM2B_DIGEST hmac; // authHMAC for comparing
685 // Compute authHMAC
686 ComputeCommandHMAC(sessionIndex, cpHash, &hmac);
687 // Compare the input HMAC with the authHMAC computed above.
688 if(!Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &hmac.b))
689 {
690 // If an HMAC session has a failure, invoke the anti-hammering
691 // if it applies to the authorized entity or the session.
692 // Otherwise, just indicate that the authorization is bad.
693 return IncrementLockout(sessionIndex);
694 }
695 return TPM_RC_SUCCESS;
696}
697//
698//
699// CheckPolicyAuthSession()
700//
701// This function is used to validate the authorization in a policy session. This function performs the following
702// comparisons to see if a policy authorization is properly provided. The check are:
703// a) compare policyDigest in session with authPolicy associated with the entity to be authorized;
704// b) compare timeout if applicable;
705// c) compare commandCode if applicable;
706//
707// d) compare cpHash if applicable; and
708// e) see if PCR values have changed since computed.
709// If all the above checks succeed, the handle is authorized. The order of these comparisons is not
710// important because any failure will result in the same error code.
711//
712// Error Returns Meaning
713//
714// TPM_RC_PCR_CHANGED PCR value is not current
715// TPM_RC_POLICY_FAIL policy session fails
716// TPM_RC_LOCALITY command locality is not allowed
717// TPM_RC_POLICY_CC CC doesn't match
718// TPM_RC_EXPIRED policy session has expired
719// TPM_RC_PP PP is required but not asserted
720// TPM_RC_NV_UNAVAILABLE NV is not available for write
721// TPM_RC_NV_RATE NV is rate limiting
722//
723static TPM_RC
724CheckPolicyAuthSession(
725 UINT32 sessionIndex, // IN: index of session to be processed
726 TPM_CC commandCode, // IN: command code
727 TPM2B_DIGEST *cpHash, // IN: cpHash using the algorithm of this
728 // session
729 TPM2B_DIGEST *nameHash // IN: nameHash using the session algorithm
730 )
731{
732 TPM_RC result = TPM_RC_SUCCESS;
733 SESSION *session;
734 TPM2B_DIGEST authPolicy;
735 TPMI_ALG_HASH policyAlg;
736 UINT8 locality;
737 // Initialize pointer to the auth session.
738 session = SessionGet(s_sessionHandles[sessionIndex]);
739 // If the command is TPM_RC_PolicySecret(), make sure that
740 // either password or authValue is required
741 if( commandCode == TPM_CC_PolicySecret
742 && session->attributes.isPasswordNeeded == CLEAR
743 && session->attributes.isAuthValueNeeded == CLEAR)
744 return TPM_RC_MODE;
745 // See if the PCR counter for the session is still valid.
746 if( !SessionPCRValueIsCurrent(s_sessionHandles[sessionIndex]) )
747 return TPM_RC_PCR_CHANGED;
748 // Get authPolicy.
749 policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex],
750 &authPolicy);
751 // Compare authPolicy.
752 if(!Memory2BEqual(&session->u2.policyDigest.b, &authPolicy.b))
753 return TPM_RC_POLICY_FAIL;
754 // Policy is OK so check if the other factors are correct
755 // Compare policy hash algorithm.
756 if(policyAlg != session->authHashAlg)
757 return TPM_RC_POLICY_FAIL;
758 // Compare timeout.
759 if(session->timeOut != 0)
760 {
761 // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE
762 // or TPM_RC_NV_RATE error may be returned here.
763 result = NvIsAvailable();
764 if(result != TPM_RC_SUCCESS)
765 return result;
766 if(session->timeOut < go.clock)
767 return TPM_RC_EXPIRED;
768 }
769 // If command code is provided it must match
770 if(session->commandCode != 0)
771 {
772 if(session->commandCode != commandCode)
773 return TPM_RC_POLICY_CC;
774 }
775 else
776 {
777 // If command requires a DUP or ADMIN authorization, the session must have
778 // command code set.
779 AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex);
780 if(role == AUTH_ADMIN || role == AUTH_DUP)
781 return TPM_RC_POLICY_FAIL;
782 }
783 // Check command locality.
784 {
785 BYTE sessionLocality[sizeof(TPMA_LOCALITY)];
786 BYTE *buffer = sessionLocality;
787 // Get existing locality setting in canonical form
788 TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL);
789 // See if the locality has been set
790 if(sessionLocality[0] != 0)
791 {
792 // If so, get the current locality
793 locality = _plat__LocalityGet();
794 if (locality < 5)
795 {
796 if( ((sessionLocality[0] & (1 << locality)) == 0)
797 || sessionLocality[0] > 31)
798 return TPM_RC_LOCALITY;
799 }
800 else if (locality > 31)
801 {
802 if(sessionLocality[0] != locality)
803 return TPM_RC_LOCALITY;
804 }
805 else
806 {
807 // Could throw an assert here but a locality error is just
808 // as good. It just means that, whatever the locality is, it isn't
809 // the locality requested so...
810 return TPM_RC_LOCALITY;
811 }
812 }
813 } // end of locality check
814 // Check physical presence.
815 if( session->attributes.isPPRequired == SET
816 && !_plat__PhysicalPresenceAsserted())
817 return TPM_RC_PP;
818 // Compare cpHash/nameHash if defined, or if the command requires an ADMIN or
819 // DUP role for this handle.
820 if(session->u1.cpHash.b.size != 0)
821 {
822 if(session->attributes.iscpHashDefined)
823 {
824 // Compare cpHash.
825 if(!Memory2BEqual(&session->u1.cpHash.b, &cpHash->b))
826 return TPM_RC_POLICY_FAIL;
827 }
828 else
829 {
830 // Compare nameHash.
831 // When cpHash is not defined, nameHash is placed in its space.
832 if(!Memory2BEqual(&session->u1.cpHash.b, &nameHash->b))
833 return TPM_RC_POLICY_FAIL;
834 }
835 }
836 if(session->attributes.checkNvWritten)
837 {
838 NV_INDEX nvIndex;
839 // If this is not an NV index, the policy makes no sense so fail it.
840 if(HandleGetType(s_associatedHandles[sessionIndex])!= TPM_HT_NV_INDEX)
841 return TPM_RC_POLICY_FAIL;
842 // Get the index data
843 NvGetIndexInfo(s_associatedHandles[sessionIndex], &nvIndex);
844 // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
845 if( (nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
846 != (session->attributes.nvWrittenState == SET))
847 return TPM_RC_POLICY_FAIL;
848 }
849 return TPM_RC_SUCCESS;
850}
851//
852//
853// RetrieveSessionData()
854//
855// This function will unmarshal the sessions in the session area of a command. The values are placed in the
856// arrays that are defined at the beginning of this file. The normal unmarshaling errors are possible.
857//
858// Error Returns Meaning
859//
860// TPM_RC_SUCCSS unmarshaled without error
861// TPM_RC_SIZE the number of bytes unmarshaled is not the same as the value for
862// authorizationSize in the command
863//
864static TPM_RC
865RetrieveSessionData (
866 TPM_CC commandCode, // IN: command code
867 UINT32 *sessionCount, // OUT: number of sessions found
868 BYTE *sessionBuffer, // IN: pointer to the session buffer
869 INT32 bufferSize // IN: size of the session buffer
870 )
871{
872 int sessionIndex;
873 int i;
874 TPM_RC result;
875 SESSION *session;
876 TPM_HT sessionType;
877 s_decryptSessionIndex = UNDEFINED_INDEX;
878 s_encryptSessionIndex = UNDEFINED_INDEX;
879 s_auditSessionIndex = UNDEFINED_INDEX;
880 for(sessionIndex = 0; bufferSize > 0; sessionIndex++)
881 {
882 // If maximum allowed number of sessions has been parsed, return a size
883 // error with a session number that is larger than the number of allowed
884 // sessions
885 if(sessionIndex == MAX_SESSION_NUM)
886 return TPM_RC_SIZE + TPM_RC_S + g_rcIndex[sessionIndex+1];
887 // make sure that the associated handle for each session starts out
888 // unassigned
889 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
890 // First parameter: Session handle.
891 result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
Vadim Bendebury3d5312a2015-06-01 18:19:06 -0700892 &sessionBuffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -0700893 if(result != TPM_RC_SUCCESS)
894 return result + TPM_RC_S + g_rcIndex[sessionIndex];
895 // Second parameter: Nonce.
896 result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
897 &sessionBuffer, &bufferSize);
898 if(result != TPM_RC_SUCCESS)
899 return result + TPM_RC_S + g_rcIndex[sessionIndex];
900 // Third parameter: sessionAttributes.
901 result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
902 &sessionBuffer, &bufferSize);
903 if(result != TPM_RC_SUCCESS)
904 return result + TPM_RC_S + g_rcIndex[sessionIndex];
905 // Fourth parameter: authValue (PW or HMAC).
906 result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
907 &sessionBuffer, &bufferSize);
908 if(result != TPM_RC_SUCCESS)
909 return result + TPM_RC_S + g_rcIndex[sessionIndex];
910 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
911 {
912 // A PWAP session needs additional processing.
913 // Can't have any attributes set other than continueSession bit
914 if( s_attributes[sessionIndex].encrypt
915 || s_attributes[sessionIndex].decrypt
916 || s_attributes[sessionIndex].audit
917 || s_attributes[sessionIndex].auditExclusive
918 || s_attributes[sessionIndex].auditReset
919 )
920 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
921 // The nonce size must be zero.
922 if(s_nonceCaller[sessionIndex].t.size != 0)
923 return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex];
924 continue;
925 }
926 // For not password sessions...
927 // Find out if the session is loaded.
928 if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
929 return TPM_RC_REFERENCE_S0 + sessionIndex;
930 sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
931 session = SessionGet(s_sessionHandles[sessionIndex]);
932 // Check if the session is an HMAC/policy session.
933 if( ( session->attributes.isPolicy == SET
934 && sessionType == TPM_HT_HMAC_SESSION
935 )
936 || ( session->attributes.isPolicy == CLEAR
937 && sessionType == TPM_HT_POLICY_SESSION
938 )
939 )
940 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
941 // Check that this handle has not previously been used.
942 for(i = 0; i < sessionIndex; i++)
943 {
944 if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
945 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
946 }
947 // If the session is used for parameter encryption or audit as well, set
948 // the corresponding indices.
949 // First process decrypt.
950 if(s_attributes[sessionIndex].decrypt)
951 {
952 // Check if the commandCode allows command parameter encryption.
953 if(DecryptSize(commandCode) == 0)
954 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
955 // Encrypt attribute can only appear in one session
956 if(s_decryptSessionIndex != UNDEFINED_INDEX)
957 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
958 // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
959 if(session->symmetric.algorithm == TPM_ALG_NULL)
960 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
961 // All checks passed, so set the index for the session used to decrypt
962 // a command parameter.
963 s_decryptSessionIndex = sessionIndex;
964 }
965 // Now process encrypt.
966 if(s_attributes[sessionIndex].encrypt)
967 {
968 // Check if the commandCode allows response parameter encryption.
969 if(EncryptSize(commandCode) == 0)
970 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
971 // Encrypt attribute can only appear in one session.
972 if(s_encryptSessionIndex != UNDEFINED_INDEX)
973 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
974 // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
975 if(session->symmetric.algorithm == TPM_ALG_NULL)
976 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
977 // All checks passed, so set the index for the session used to encrypt
978 // a response parameter.
979 s_encryptSessionIndex = sessionIndex;
980 }
981 // At last process audit.
982 if(s_attributes[sessionIndex].audit)
983 {
984 // Audit attribute can only appear in one session.
985 if(s_auditSessionIndex != UNDEFINED_INDEX)
986 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
987 // An audit session can not be policy session.
988 if( HandleGetType(s_sessionHandles[sessionIndex])
989 == TPM_HT_POLICY_SESSION)
990 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
991 // If this is a reset of the audit session, or the first use
992 // of the session as an audit session, it doesn't matter what
993 // the exclusive state is. The session will become exclusive.
994 if( s_attributes[sessionIndex].auditReset == CLEAR
995 && session->attributes.isAudit == SET)
996 {
997 // Not first use or reset. If auditExlusive is SET, then this
998 // session must be the current exclusive session.
999 if( s_attributes[sessionIndex].auditExclusive == SET
1000 && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
1001 return TPM_RC_EXCLUSIVE;
1002 }
1003 s_auditSessionIndex = sessionIndex;
1004 }
1005 // Initialize associated handle as undefined. This will be changed when
1006 // the handles are processed.
1007 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1008 }
1009 // Set the number of sessions found.
1010 *sessionCount = sessionIndex;
1011 return TPM_RC_SUCCESS;
1012}
1013//
1014//
1015// CheckLockedOut()
1016//
1017// This function checks to see if the TPM is in lockout. This function should only be called if the entity being
1018// checked is subject to DA protection. The TPM is in lockout if the NV is not available and a DA write is
1019// pending. Otherwise the TPM is locked out if checking for lockoutAuth (lockoutAuthCheck == TRUE) and
1020// use of lockoutAuth is disabled, or failedTries >= maxTries
1021//
1022// Error Returns Meaning
1023//
1024// TPM_RC_NV_RATE NV is rate limiting
1025// TPM_RC_NV_UNAVAILABLE NV is not available at this time
1026// TPM_RC_LOCKOUT TPM is in lockout
1027//
1028static TPM_RC
1029CheckLockedOut(
1030 BOOL lockoutAuthCheck // IN: TRUE if checking is for lockoutAuth
1031 )
1032{
1033 TPM_RC result;
1034 // If NV is unavailable, and current cycle state recorded in NV is not
1035 // SHUTDOWN_NONE, refuse to check any authorization because we would
1036 // not be able to handle a DA failure.
1037 result = NvIsAvailable();
1038 if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE)
1039 return result;
1040 // Check if DA info needs to be updated in NV.
1041 if(s_DAPendingOnNV)
1042 {
1043 // If NV is accessible, ...
1044 if(result == TPM_RC_SUCCESS)
1045 {
1046 // ... write the pending DA data and proceed.
1047 NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED,
1048 &gp.lockOutAuthEnabled);
1049 NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
1050 g_updateNV = TRUE;
1051 s_DAPendingOnNV = FALSE;
1052 }
1053 else
1054 {
1055 // Otherwise no authorization can be checked.
1056 return result;
1057 }
1058 }
1059 // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1060 // is disabled...
1061 if(lockoutAuthCheck)
1062 {
1063 if(gp.lockOutAuthEnabled == FALSE)
1064 return TPM_RC_LOCKOUT;
1065 }
1066 else
1067 {
1068 // ... or if the number of failed tries has been maxed out.
1069 if(gp.failedTries >= gp.maxTries)
1070 return TPM_RC_LOCKOUT;
1071 }
1072 return TPM_RC_SUCCESS;
1073}
1074//
1075//
1076// CheckAuthSession()
1077//
1078// This function checks that the authorization session properly authorizes the use of the associated handle.
1079//
1080// Error Returns Meaning
1081//
1082// TPM_RC_LOCKOUT entity is protected by DA and TPM is in lockout, or TPM is locked out
1083// on NV update pending on DA parameters
1084// TPM_RC_PP Physical Presence is required but not provided
1085// TPM_RC_AUTH_FAIL HMAC or PW authorization failed with DA side-effects (can be a
1086// policy session)
1087// TPM_RC_BAD_AUTH HMAC or PW authorization failed without DA side-effects (can be a
1088// policy session)
1089// TPM_RC_POLICY_FAIL if policy session fails
1090// TPM_RC_POLICY_CC command code of policy was wrong
1091// TPM_RC_EXPIRED the policy session has expired
1092// TPM_RC_PCR ???
1093// TPM_RC_AUTH_UNAVAILABLE authValue or authPolicy unavailable
1094//
1095static TPM_RC
1096CheckAuthSession(
1097 TPM_CC commandCode, // IN: commandCode
1098 UINT32 sessionIndex, // IN: index of session to be processed
1099 TPM2B_DIGEST *cpHash, // IN: cpHash
1100 TPM2B_DIGEST *nameHash // IN: nameHash
1101//
1102 )
1103{
1104 TPM_RC result;
1105 SESSION *session = NULL;
1106 TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
1107 TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex];
1108 TPM_HT sessionHandleType = HandleGetType(sessionHandle);
1109 pAssert(sessionHandle != TPM_RH_UNASSIGNED);
1110 if(sessionHandle != TPM_RS_PW)
1111 session = SessionGet(sessionHandle);
1112 pAssert(sessionHandleType != TPM_HT_POLICY_SESSION || session != NULL);
1113 // If the authorization session is not a policy session, or if the policy
1114 // session requires authorization, then check lockout.
1115 if( sessionHandleType != TPM_HT_POLICY_SESSION
1116 || session->attributes.isAuthValueNeeded
1117 || session->attributes.isPasswordNeeded)
1118 {
1119 // See if entity is subject to lockout.
1120 if(!IsDAExempted(associatedHandle))
1121 {
1122 // If NV is unavailable, and current cycle state recorded in NV is not
1123 // SHUTDOWN_NONE, refuse to check any authorization because we would
1124 // not be able to handle a DA failure.
1125 result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
1126 if(result != TPM_RC_SUCCESS)
1127 return result;
1128 }
1129 }
1130 if(associatedHandle == TPM_RH_PLATFORM)
1131 {
1132 // If the physical presence is required for this command, check for PP
1133 // assertion. If it isn't asserted, no point going any further.
1134 if( PhysicalPresenceIsRequired(commandCode)
1135 && !_plat__PhysicalPresenceAsserted()
1136 )
1137 return TPM_RC_PP;
1138 }
1139 // If a policy session is required, make sure that it is being used.
1140 if( IsPolicySessionRequired(commandCode, sessionIndex)
1141 && sessionHandleType != TPM_HT_POLICY_SESSION)
1142 return TPM_RC_AUTH_TYPE;
1143 // If this is a PW authorization, check it and return.
1144 if(sessionHandle == TPM_RS_PW)
1145 {
1146 if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1147 return CheckPWAuthSession(sessionIndex);
1148 else
1149 return TPM_RC_AUTH_UNAVAILABLE;
1150 }
1151 // If this is a policy session, ...
1152 if(sessionHandleType == TPM_HT_POLICY_SESSION)
1153 {
1154 // ... see if the entity has a policy, ...
1155 if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex))
1156 return TPM_RC_AUTH_UNAVAILABLE;
1157 // ... and check the policy session.
1158 result = CheckPolicyAuthSession(sessionIndex, commandCode,
1159 cpHash, nameHash);
1160 if (result != TPM_RC_SUCCESS)
1161 return result;
1162 }
1163 else
1164 {
1165 // For non policy, the entity being accessed must allow authorization
1166 // with an auth value. This is required even if the auth value is not
1167 // going to be used in an HMAC because it is bound.
1168 if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1169 return TPM_RC_AUTH_UNAVAILABLE;
1170 }
1171 // At this point, the session must be either a policy or an HMAC session.
1172 session = SessionGet(s_sessionHandles[sessionIndex]);
1173 if( sessionHandleType == TPM_HT_POLICY_SESSION
1174 && session->attributes.isPasswordNeeded == SET)
1175 {
1176 // For policy session that requires a password, check it as PWAP session.
1177 return CheckPWAuthSession(sessionIndex);
1178 }
1179 else
1180 {
1181 // For other policy or HMAC sessions, have its HMAC checked.
1182 return CheckSessionHMAC(sessionIndex, cpHash);
1183 }
1184}
1185#ifdef TPM_CC_GetCommandAuditDigest
1186//
1187//
1188// CheckCommandAudit()
1189//
1190// This function checks if the current command may trigger command audit, and if it is safe to perform the
1191// action.
1192//
1193// Error Returns Meaning
1194//
1195// TPM_RC_NV_UNAVAILABLE NV is not available for write
1196// TPM_RC_NV_RATE NV is rate limiting
1197//
1198static TPM_RC
1199CheckCommandAudit(
1200 TPM_CC commandCode, // IN: Command code
1201 UINT32 handleNum, // IN: number of element in handle array
1202 TPM_HANDLE handles[], // IN: array of handle
1203 BYTE *parmBufferStart, // IN: start of parameter buffer
1204 UINT32 parmBufferSize // IN: size of parameter buffer
1205 )
1206{
1207 TPM_RC result = TPM_RC_SUCCESS;
1208 // If audit is implemented, need to check to see if auditing is being done
1209 // for this command.
1210 if(CommandAuditIsRequired(commandCode))
1211 {
1212 // If the audit digest is clear and command audit is required, NV must be
1213 // available so that TPM2_GetCommandAuditDigest() is able to increment
1214 // audit counter. If NV is not available, the function bails out to prevent
1215 // the TPM from attempting an operation that would fail anyway.
1216 if( gr.commandAuditDigest.t.size == 0
1217 || commandCode == TPM_CC_GetCommandAuditDigest)
1218 {
1219 result = NvIsAvailable();
1220 if(result != TPM_RC_SUCCESS)
1221 return result;
1222 }
1223 ComputeCpHash(gp.auditHashAlg, commandCode, handleNum,
1224 handles, parmBufferSize, parmBufferStart,
1225 &s_cpHashForCommandAudit, NULL);
1226 }
1227 return TPM_RC_SUCCESS;
1228}
1229#endif
1230//
1231//
1232// ParseSessionBuffer()
1233//
1234// This function is the entry function for command session processing. It iterates sessions in session area
1235// and reports if the required authorization has been properly provided. It also processes audit session and
1236// passes the information of encryption sessions to parameter encryption module.
1237//
1238// Error Returns Meaning
1239//
1240// various parsing failure or authorization failure
1241//
1242TPM_RC
1243ParseSessionBuffer(
1244 TPM_CC commandCode, // IN: Command code
1245 UINT32 handleNum, // IN: number of element in handle array
1246 TPM_HANDLE handles[], // IN: array of handle
1247 BYTE *sessionBufferStart, // IN: start of session buffer
1248 UINT32 sessionBufferSize, // IN: size of session buffer
1249 BYTE *parmBufferStart, // IN: start of parameter buffer
1250 UINT32 parmBufferSize // IN: size of parameter buffer
1251 )
1252{
1253 TPM_RC result;
1254 UINT32 i;
1255 INT32 size = 0;
1256 TPM2B_AUTH extraKey;
1257 UINT32 sessionIndex;
1258 SESSION *session;
1259 TPM2B_DIGEST cpHash;
1260 TPM2B_DIGEST nameHash;
1261 TPM_ALG_ID cpHashAlg = TPM_ALG_NULL; // algID for the last computed
1262 // cpHash
1263 // Check if a command allows any session in its session area.
1264 if(!IsSessionAllowed(commandCode))
1265 return TPM_RC_AUTH_CONTEXT;
1266 // Default-initialization.
1267 s_sessionNum = 0;
1268 cpHash.t.size = 0;
1269 result = RetrieveSessionData(commandCode, &s_sessionNum,
1270 sessionBufferStart, sessionBufferSize);
1271 if(result != TPM_RC_SUCCESS)
1272 return result;
1273 // There is no command in the TPM spec that has more handles than
1274 // MAX_SESSION_NUM.
1275 pAssert(handleNum <= MAX_SESSION_NUM);
1276 // Associate the session with an authorization handle.
1277 for(i = 0; i < handleNum; i++)
1278 {
1279 if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1280 {
1281 // If the received session number is less than the number of handle
1282 // that requires authorization, an error should be returned.
1283 // Note: for all the TPM 2.0 commands, handles requiring
1284 // authorization come first in a command input.
1285 if(i > (s_sessionNum - 1))
1286 return TPM_RC_AUTH_MISSING;
1287 // Record the handle associated with the authorization session
1288 s_associatedHandles[i] = handles[i];
1289 }
1290 }
1291 // Consistency checks are done first to avoid auth failure when the command
1292 // will not be executed anyway.
1293 for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++)
1294 {
1295 // PW session must be an authorization session
1296 if(s_sessionHandles[sessionIndex] == TPM_RS_PW )
1297 {
1298 if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
1299 return TPM_RC_HANDLE + g_rcIndex[sessionIndex];
1300 }
1301 else
1302 {
1303 session = SessionGet(s_sessionHandles[sessionIndex]);
1304 // A trial session can not appear in session area, because it cannot
1305 // be used for authorization, audit or encrypt/decrypt.
1306 if(session->attributes.isTrialPolicy == SET)
1307 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1308 // See if the session is bound to a DA protected entity
1309 // NOTE: Since a policy session is never bound, a policy is still
1310 // usable even if the object is DA protected and the TPM is in
1311 // lockout.
1312 if(session->attributes.isDaBound == SET)
1313 {
1314 result = CheckLockedOut(session->attributes.isLockoutBound == SET);
1315 if(result != TPM_RC_SUCCESS)
1316 return result;
1317 }
1318 // If the current cpHash is the right one, don't re-compute.
1319 if(cpHashAlg != session->authHashAlg) // different so compute
1320 {
1321 cpHashAlg = session->authHashAlg; // save this new algID
1322 ComputeCpHash(session->authHashAlg, commandCode, handleNum,
1323 handles, parmBufferSize, parmBufferStart,
1324 &cpHash, &nameHash);
1325 }
1326 // If this session is for auditing, save the cpHash.
1327 if(s_attributes[sessionIndex].audit)
1328 s_cpHashForAudit = cpHash;
1329 }
1330 // if the session has an associated handle, check the auth
1331 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
1332 {
1333 result = CheckAuthSession(commandCode, sessionIndex,
1334 &cpHash, &nameHash);
1335 if(result != TPM_RC_SUCCESS)
1336 return RcSafeAddToResult(result,
1337 TPM_RC_S + g_rcIndex[sessionIndex]);
1338 }
1339 else
1340 {
1341 // a session that is not for authorization must either be encrypt,
1342 // decrypt, or audit
1343 if( s_attributes[sessionIndex].audit == CLEAR
1344 && s_attributes[sessionIndex].encrypt == CLEAR
1345 && s_attributes[sessionIndex].decrypt == CLEAR)
1346 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1347 // check HMAC for encrypt/decrypt/audit only sessions
1348 result = CheckSessionHMAC(sessionIndex, &cpHash);
1349 if(result != TPM_RC_SUCCESS)
1350 return RcSafeAddToResult(result,
1351 TPM_RC_S + g_rcIndex[sessionIndex]);
1352 }
1353 }
1354#ifdef TPM_CC_GetCommandAuditDigest
1355 // Check if the command should be audited.
1356 result = CheckCommandAudit(commandCode, handleNum, handles,
1357 parmBufferStart, parmBufferSize);
1358 if(result != TPM_RC_SUCCESS)
1359 return result; // No session number to reference
1360#endif
1361 // Decrypt the first parameter if applicable. This should be the last operation
1362 // in session processing.
1363 // If the encrypt session is associated with a handle and the handle's
1364 // authValue is available, then authValue is concatenated with sessionAuth to
1365 // generate encryption key, no matter if the handle is the session bound entity
1366 // or not.
1367 if(s_decryptSessionIndex != UNDEFINED_INDEX)
1368 {
1369 // Get size of the leading size field in decrypt parameter
1370 if( s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED
1371 && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex],
1372 commandCode,
1373 s_decryptSessionIndex)
1374 )
1375 {
1376 extraKey.b.size=
1377 EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex],
1378 &extraKey.t.buffer);
1379 }
1380 else
1381 {
1382 extraKey.b.size = 0;
1383 }
1384 size = DecryptSize(commandCode);
1385 result = CryptParameterDecryption(
1386 s_sessionHandles[s_decryptSessionIndex],
1387 &s_nonceCaller[s_decryptSessionIndex].b,
1388 parmBufferSize, (UINT16)size,
1389 &extraKey,
1390 parmBufferStart);
1391 if(result != TPM_RC_SUCCESS)
1392 return RcSafeAddToResult(result,
1393 TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
1394 }
1395 return TPM_RC_SUCCESS;
1396}
1397//
1398//
1399// CheckAuthNoSession()
1400//
1401// Function to process a command with no session associated. The function makes sure all the handles in
1402// the command require no authorization.
1403//
1404//
1405//
1406// Error Returns Meaning
1407//
1408// TPM_RC_AUTH_MISSING failure - one or more handles require auth
1409//
1410TPM_RC
1411CheckAuthNoSession(
1412 TPM_CC commandCode, // IN: Command Code
1413 UINT32 handleNum, // IN: number of handles in command
1414 TPM_HANDLE handles[], // IN: array of handle
1415 BYTE *parmBufferStart, // IN: start of parameter buffer
1416 UINT32 parmBufferSize // IN: size of parameter buffer
1417 )
1418{
1419 UINT32 i;
1420 TPM_RC result = TPM_RC_SUCCESS;
1421 // Check if the commandCode requires authorization
1422 for(i = 0; i < handleNum; i++)
1423 {
1424 if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1425 return TPM_RC_AUTH_MISSING;
1426 }
1427#ifdef TPM_CC_GetCommandAuditDigest
1428 // Check if the command should be audited.
1429 result = CheckCommandAudit(commandCode, handleNum, handles,
1430 parmBufferStart, parmBufferSize);
1431 if(result != TPM_RC_SUCCESS) return result;
1432#endif
1433 // Initialize number of sessions to be 0
1434 s_sessionNum = 0;
1435 return TPM_RC_SUCCESS;
1436}
1437//
1438//
1439// Response Session Processing
1440//
1441// Introduction
1442//
1443// The following functions build the session area in a response, and handle the audit sessions (if present).
1444//
1445// ComputeRpHash()
1446//
1447// Function to compute rpHash (Response Parameter Hash). The rpHash is only computed if there is an
1448// HMAC authorization session and the return code is TPM_RC_SUCCESS.
1449//
1450static void
1451ComputeRpHash(
1452 TPM_ALG_ID hashAlg, // IN: hash algorithm to compute rpHash
1453 TPM_CC commandCode, // IN: commandCode
1454 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1455 BYTE *resParmBuffer, // IN: response parameter buffer
1456 TPM2B_DIGEST *rpHash // OUT: rpHash
1457 )
1458{
1459 // The command result in rpHash is always TPM_RC_SUCCESS.
1460 TPM_RC responseCode = TPM_RC_SUCCESS;
1461 HASH_STATE hashState;
1462 // rpHash := hash(responseCode || commandCode || parameters)
1463 // Initiate hash creation.
1464 rpHash->t.size = CryptStartHash(hashAlg, &hashState);
1465 // Add hash constituents.
1466 CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode);
1467 CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
1468 CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer);
1469 // Complete hash computation.
1470 CryptCompleteHash2B(&hashState, &rpHash->b);
1471 return;
1472}
1473//
1474//
1475// InitAuditSession()
1476//
1477// This function initializes the audit data in an audit session.
1478//
1479static void
1480InitAuditSession(
1481 SESSION *session // session to be initialized
1482 )
1483{
1484 // Mark session as an audit session.
1485 session->attributes.isAudit = SET;
1486 // Audit session can not be bound.
1487 session->attributes.isBound = CLEAR;
1488 // Size of the audit log is the size of session hash algorithm digest.
1489 session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
1490 // Set the original digest value to be 0.
1491 MemorySet(&session->u2.auditDigest.t.buffer,
1492 0,
1493 session->u2.auditDigest.t.size);
1494 return;
1495}
1496//
1497//
1498// Audit()
1499//
1500// This function updates the audit digest in an audit session.
1501//
1502static void
1503Audit(
1504 SESSION *auditSession, // IN: loaded audit session
1505 TPM_CC commandCode, // IN: commandCode
1506 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1507 BYTE *resParmBuffer // IN: response parameter buffer
1508 )
1509{
1510 TPM2B_DIGEST rpHash; // rpHash for response
1511 HASH_STATE hashState;
1512 // Compute rpHash
1513 ComputeRpHash(auditSession->authHashAlg,
1514 commandCode,
1515 resParmBufferSize,
1516 resParmBuffer,
1517 &rpHash);
1518 // auditDigestnew := hash (auditDigestold || cpHash || rpHash)
1519 // Start hash computation.
1520 CryptStartHash(auditSession->authHashAlg, &hashState);
1521 // Add old digest.
1522 CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b);
1523 // Add cpHash and rpHash.
1524 CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b);
1525 CryptUpdateDigest2B(&hashState, &rpHash.b);
1526 // Finalize the hash.
1527 CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b);
1528 return;
1529}
1530#ifdef TPM_CC_GetCommandAuditDigest
1531//
1532//
1533// CommandAudit()
1534//
1535// This function updates the command audit digest.
1536//
1537static void
1538CommandAudit(
1539 TPM_CC commandCode, // IN: commandCode
1540 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1541 BYTE *resParmBuffer // IN: response parameter buffer
1542 )
1543{
1544 if(CommandAuditIsRequired(commandCode))
1545 {
1546 TPM2B_DIGEST rpHash; // rpHash for response
1547 HASH_STATE hashState;
1548 // Compute rpHash.
1549 ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize,
1550 resParmBuffer, &rpHash);
1551 // If the digest.size is one, it indicates the special case of changing
1552 // the audit hash algorithm. For this case, no audit is done on exit.
1553 // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1554 // force an update to the NV on exit so that the change in digest will
1555 // be recorded. So, it is safe to exit here without setting any flags
1556 // because the digest change will be written to NV when this code exits.
1557 if(gr.commandAuditDigest.t.size == 1)
1558 {
1559 gr.commandAuditDigest.t.size = 0;
1560 return;
1561 }
1562 // If the digest size is zero, need to start a new digest and increment
1563 // the audit counter.
1564 if(gr.commandAuditDigest.t.size == 0)
1565 {
1566 gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg);
1567 MemorySet(gr.commandAuditDigest.t.buffer,
1568 0,
1569 gr.commandAuditDigest.t.size);
1570 // Bump the counter and save its value to NV.
1571 gp.auditCounter++;
1572 NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
1573 g_updateNV = TRUE;
1574//
1575 }
1576 // auditDigestnew := hash (auditDigestold || cpHash || rpHash)
1577 // Start hash computation.
1578 CryptStartHash(gp.auditHashAlg, &hashState);
1579 // Add old digest.
1580 CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b);
1581 // Add cpHash
1582 CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b);
1583 // Add rpHash
1584 CryptUpdateDigest2B(&hashState, &rpHash.b);
1585 // Finalize the hash.
1586 CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b);
1587 }
1588 return;
1589}
1590#endif
1591//
1592//
1593// UpdateAuditSessionStatus()
1594//
1595// Function to update the internal audit related states of a session. It
1596// a) initializes the session as audit session and sets it to be exclusive if this is the first time it is used for
1597// audit or audit reset was requested;
1598// b) reports exclusive audit session;
1599// c) extends audit log; and
1600// d) clears exclusive audit session if no audit session found in the command.
1601//
1602static void
1603UpdateAuditSessionStatus(
1604 TPM_CC commandCode, // IN: commandCode
1605 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1606 BYTE *resParmBuffer // IN: response parameter buffer
1607 )
1608{
1609 UINT32 i;
1610 TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
1611 // Iterate through sessions
1612 for (i = 0; i < s_sessionNum; i++)
1613 {
1614 SESSION *session;
1615 // PW session do not have a loaded session and can not be an audit
1616 // session either. Skip it.
1617 if(s_sessionHandles[i] == TPM_RS_PW) continue;
1618 session = SessionGet(s_sessionHandles[i]);
1619 // If a session is used for audit
1620 if(s_attributes[i].audit == SET)
1621 {
1622 // An audit session has been found
1623 auditSession = s_sessionHandles[i];
1624 // If the session has not been an audit session yet, or
1625 // the auditSetting bits indicate a reset, initialize it and set
1626 // it to be the exclusive session
1627 if( session->attributes.isAudit == CLEAR
1628 || s_attributes[i].auditReset == SET
1629 )
1630 {
1631 InitAuditSession(session);
1632 g_exclusiveAuditSession = auditSession;
1633 }
1634 else
1635 {
1636 // Check if the audit session is the current exclusive audit
1637 // session and, if not, clear previous exclusive audit session.
1638 if(g_exclusiveAuditSession != auditSession)
1639 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1640 }
1641 // Report audit session exclusivity.
1642 if(g_exclusiveAuditSession == auditSession)
1643 {
1644 s_attributes[i].auditExclusive = SET;
1645 }
1646 else
1647 {
1648 s_attributes[i].auditExclusive = CLEAR;
1649 }
1650 // Extend audit log.
1651 Audit(session, commandCode, resParmBufferSize, resParmBuffer);
1652 }
1653 }
1654 // If no audit session is found in the command, and the command allows
1655 // a session then, clear the current exclusive
1656 // audit session.
1657 if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode))
1658 {
1659 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1660 }
1661 return;
1662}
1663//
1664//
1665// ComputeResponseHMAC()
1666//
1667// Function to compute HMAC for authorization session in a response.
1668//
1669static void
1670ComputeResponseHMAC(
1671 UINT32 sessionIndex, // IN: session index to be processed
1672 SESSION *session, // IN: loaded session
1673 TPM_CC commandCode, // IN: commandCode
1674 TPM2B_NONCE *nonceTPM, // IN: nonceTPM
1675 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1676 BYTE *resParmBuffer, // IN: response parameter buffer
1677 TPM2B_DIGEST *hmac // OUT: authHMAC
1678 )
1679{
1680 TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1681 TPM2B_KEY key; // HMAC key
1682 BYTE marshalBuffer[sizeof(TPMA_SESSION)];
1683 BYTE *buffer;
1684 UINT32 marshalSize;
1685 HMAC_STATE hmacState;
1686 TPM2B_DIGEST rp_hash;
1687//
1688 // Compute rpHash.
1689 ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize,
1690 resParmBuffer, &rp_hash);
1691 // Generate HMAC key
1692 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1693 // Check if the session has an associated handle and the associated entity is
1694 // the one that the session is bound to.
1695 // If not bound, add the authValue of this entity to the HMAC key.
1696 if( s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED
1697 && !( HandleGetType(s_sessionHandles[sessionIndex])
1698 == TPM_HT_POLICY_SESSION
1699 && session->attributes.isAuthValueNeeded == CLEAR)
1700 && !session->attributes.requestWasBound)
1701 {
1702 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
1703 key.t.size = key.t.size +
1704 EntityGetAuthValue(s_associatedHandles[sessionIndex],
1705 (AUTH_VALUE *)&key.t.buffer[key.t.size]);
1706 }
1707 // if the HMAC key size for a policy session is 0, the response HMAC is
1708 // computed according to the input HMAC
1709 if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1710 && key.t.size == 0
1711 && s_inputAuthValues[sessionIndex].t.size == 0)
1712 {
1713 hmac->t.size = 0;
1714 return;
1715 }
1716 // Start HMAC computation.
1717 hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
1718 // Add hash components.
1719 CryptUpdateDigest2B(&hmacState, &rp_hash.b);
1720 CryptUpdateDigest2B(&hmacState, &nonceTPM->b);
1721 CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
1722 // Add session attributes.
1723 buffer = marshalBuffer;
1724 marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL);
1725 CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
1726 // Finalize HMAC.
1727 CryptCompleteHMAC2B(&hmacState, &hmac->b);
1728 return;
1729}
1730//
1731//
1732// BuildSingleResponseAuth()
1733//
1734// Function to compute response for an authorization session.
1735//
1736static void
1737BuildSingleResponseAuth(
1738 UINT32 sessionIndex, // IN: session index to be processed
1739 TPM_CC commandCode, // IN: commandCode
1740 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1741 BYTE *resParmBuffer, // IN: response parameter buffer
1742 TPM2B_AUTH *auth // OUT: authHMAC
1743 )
1744//
1745{
1746 // For password authorization, field is empty.
1747 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
1748 {
1749 auth->t.size = 0;
1750 }
1751 else
1752 {
1753 // Fill in policy/HMAC based session response.
1754 SESSION *session = SessionGet(s_sessionHandles[sessionIndex]);
1755 // If the session is a policy session with isPasswordNeeded SET, the auth
1756 // field is empty.
1757 if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1758 && session->attributes.isPasswordNeeded == SET)
1759 auth->t.size = 0;
1760 else
1761 // Compute response HMAC.
1762 ComputeResponseHMAC(sessionIndex,
1763 session,
1764 commandCode,
1765 &session->nonceTPM,
1766 resParmBufferSize,
1767 resParmBuffer,
1768 auth);
1769 }
1770 return;
1771}
1772//
1773//
1774// UpdateTPMNonce()
1775//
1776// Updates TPM nonce in both internal session or response if applicable.
1777//
1778static void
1779UpdateTPMNonce(
1780 UINT16 noncesSize, // IN: number of elements in 'nonces' array
1781 TPM2B_NONCE nonces[] // OUT: nonceTPM
1782 )
1783{
1784 UINT32 i;
1785 pAssert(noncesSize >= s_sessionNum);
1786 for(i = 0; i < s_sessionNum; i++)
1787 {
1788 SESSION *session;
1789 // For PW session, nonce is 0.
1790 if(s_sessionHandles[i] == TPM_RS_PW)
1791 {
1792 nonces[i].t.size = 0;
1793 continue;
1794 }
1795 session = SessionGet(s_sessionHandles[i]);
1796 // Update nonceTPM in both internal session and response.
1797 CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
1798 nonces[i] = session->nonceTPM;
1799 }
1800 return;
1801}
1802//
1803//
1804// UpdateInternalSession()
1805//
1806// Updates internal sessions:
1807//
1808//
1809// a) Restarts session time, and
1810// b) Clears a policy session since nonce is rolling.
1811//
1812static void
1813UpdateInternalSession(
1814 void
1815 )
1816{
1817 UINT32 i;
1818 for(i = 0; i < s_sessionNum; i++)
1819 {
1820 // For PW session, no update.
1821 if(s_sessionHandles[i] == TPM_RS_PW) continue;
1822 if(s_attributes[i].continueSession == CLEAR)
1823 {
1824 // Close internal session.
1825 SessionFlush(s_sessionHandles[i]);
1826 }
1827 else
1828 {
1829 // If nonce is rolling in a policy session, the policy related data
1830 // will be re-initialized.
1831 if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION)
1832 {
1833 SESSION *session = SessionGet(s_sessionHandles[i]);
1834 // When the nonce rolls it starts a new timing interval for the
1835 // policy session.
1836 SessionResetPolicyData(session);
1837 session->startTime = go.clock;
1838 }
1839 }
1840 }
1841 return;
1842}
1843//
1844//
1845// BuildResponseSession()
1846//
1847// Function to build Session buffer in a response.
1848//
1849void
1850BuildResponseSession(
1851 TPM_ST tag, // IN: tag
1852 TPM_CC commandCode, // IN: commandCode
1853 UINT32 resHandleSize, // IN: size of response handle buffer
1854 UINT32 resParmSize, // IN: size of response parameter buffer
1855 UINT32 *resSessionSize // OUT: response session area
1856 )
1857{
1858 BYTE *resParmBuffer;
1859 TPM2B_NONCE responseNonces[MAX_SESSION_NUM];
1860 // Compute response parameter buffer start.
1861 resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) +
1862 sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize;
1863 // For TPM_ST_SESSIONS, there is parameterSize field.
1864 if(tag == TPM_ST_SESSIONS)
1865 resParmBuffer += sizeof(UINT32);
1866 // Session nonce should be updated before parameter encryption
1867 if(tag == TPM_ST_SESSIONS)
1868 {
1869 UpdateTPMNonce(MAX_SESSION_NUM, responseNonces);
1870 // Encrypt first parameter if applicable. Parameter encryption should
1871 // happen after nonce update and before any rpHash is computed.
1872 // If the encrypt session is associated with a handle, the authValue of
1873 // this handle will be concatenated with sessionAuth to generate
1874 // encryption key, no matter if the handle is the session bound entity
1875 // or not. The authValue is added to sessionAuth only when the authValue
1876 // is available.
1877 if(s_encryptSessionIndex != UNDEFINED_INDEX)
1878 {
1879 UINT32 size;
1880 TPM2B_AUTH extraKey;
1881 // Get size of the leading size field
1882 if( s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED
1883 && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex],
1884 commandCode, s_encryptSessionIndex)
1885 )
1886 {
1887 extraKey.b.size =
1888 EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
1889 &extraKey.t.buffer);
1890 }
1891 else
1892 {
1893 extraKey.b.size = 0;
1894 }
1895 size = EncryptSize(commandCode);
1896 CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
1897 &s_nonceCaller[s_encryptSessionIndex].b,
1898 (UINT16)size,
1899 &extraKey,
1900 resParmBuffer);
1901 }
1902 }
1903 // Audit session should be updated first regardless of the tag.
1904 // A command with no session may trigger a change of the exclusivity state.
1905 UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer);
1906 // Audit command.
1907 CommandAudit(commandCode, resParmSize, resParmBuffer);
1908 // Process command with sessions.
1909 if(tag == TPM_ST_SESSIONS)
1910 {
1911 UINT32 i;
1912 BYTE *buffer;
1913 TPM2B_DIGEST responseAuths[MAX_SESSION_NUM];
1914 pAssert(s_sessionNum > 0);
1915 // Iterate over each session in the command session area, and create
1916 // corresponding sessions for response.
1917 for(i = 0; i < s_sessionNum; i++)
1918 {
1919 BuildSingleResponseAuth(
1920 i,
1921 commandCode,
1922 resParmSize,
1923 resParmBuffer,
1924 &responseAuths[i]);
1925 // Make sure that continueSession is SET on any Password session.
1926 // This makes it marginally easier for the management software
1927 // to keep track of the closed sessions.
1928 if( s_attributes[i].continueSession == CLEAR
1929 && s_sessionHandles[i] == TPM_RS_PW)
1930 {
1931 s_attributes[i].continueSession = SET;
1932 }
1933 }
1934 // Assemble Response Sessions.
1935 *resSessionSize = 0;
1936 buffer = resParmBuffer + resParmSize;
1937 for(i = 0; i < s_sessionNum; i++)
1938 {
1939 *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i],
1940 &buffer, NULL);
1941 *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i],
1942 &buffer, NULL);
1943 *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i],
1944 &buffer, NULL);
1945 }
1946 // Update internal sessions after completing response buffer computation.
1947 UpdateInternalSession();
1948 }
1949 else
1950 {
1951 // Process command with no session.
1952 *resSessionSize = 0;
1953 }
1954 return;
1955}