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