blob: 9401e49b5b68f65f2e4e0f780511d4167df179d0 [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 {
ChromeOS Developere85c65b2015-07-10 10:12:43 -0700491 name.t.size = EntityGetName(handles[i], &name.t.name);
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 {
ChromeOS Developere85c65b2015-07-10 10:12:43 -0700506 name.t.size = EntityGetName(handles[i], &name.t.name);
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;
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700566 INT32 bufferSize;
Vadim Bendebury56797522015-05-20 10:32:25 -0700567 UINT32 marshalSize;
568 HMAC_STATE hmacState;
569 TPM2B_NONCE *nonceDecrypt;
570 TPM2B_NONCE *nonceEncrypt;
571 SESSION *session;
572 TPM_HT sessionHandleType =
573 HandleGetType(s_sessionHandles[sessionIndex]);
574 nonceDecrypt = NULL;
575 nonceEncrypt = NULL;
576 // Determine if extra nonceTPM values are going to be required.
577 // If this is the first session (sessionIndex = 0) and it is an authorization
578 // session that uses an HMAC, then check if additional session nonces are to be
579 // included.
580 if( sessionIndex == 0
581 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
582 {
583 // If there is a decrypt session and if this is not the decrypt session,
584 // then an extra nonce may be needed.
585 if( s_decryptSessionIndex != UNDEFINED_INDEX
586 && s_decryptSessionIndex != sessionIndex)
587 {
588 // Will add the nonce for the decrypt session.
589 SESSION *decryptSession
590 = SessionGet(s_sessionHandles[s_decryptSessionIndex]);
591 nonceDecrypt = &decryptSession->nonceTPM;
592 }
593 // Now repeat for the encrypt session.
594 if( s_encryptSessionIndex != UNDEFINED_INDEX
595 && s_encryptSessionIndex != sessionIndex
596//
597 && s_encryptSessionIndex != s_decryptSessionIndex)
598 {
599 // Have to have the nonce for the encrypt session.
600 SESSION *encryptSession
601 = SessionGet(s_sessionHandles[s_encryptSessionIndex]);
602 nonceEncrypt = &encryptSession->nonceTPM;
603 }
604 }
605 // Continue with the HMAC processing.
606 session = SessionGet(s_sessionHandles[sessionIndex]);
607 // Generate HMAC key.
608 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
609 // Check if the session has an associated handle and if the associated entity
610 // is the one to which the session is bound. If not, add the authValue of
611 // this entity to the HMAC key.
612 // If the session is bound to the object or the session is a policy session
613 // with no authValue required, do not include the authValue in the HMAC key.
614 // Note: For a policy session, its isBound attribute is CLEARED.
615 // If the session isn't used for authorization, then there is no auth value
616 // to add
617 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
618 {
619 // used for auth so see if this is a policy session with authValue needed
620 // or an hmac session that is not bound
Vadim Bendebury3d5312a2015-06-01 18:19:06 -0700621 if (((sessionHandleType == TPM_HT_POLICY_SESSION)
622 && (session->attributes.isAuthValueNeeded == SET))
623 || ((sessionHandleType == TPM_HT_HMAC_SESSION)
624 && !IsSessionBindEntity(s_associatedHandles[sessionIndex], session))
Vadim Bendebury56797522015-05-20 10:32:25 -0700625 )
626 {
627 // add the authValue to the HMAC key
628 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
629 key.t.size = key.t.size
630 + EntityGetAuthValue(s_associatedHandles[sessionIndex],
631 (AUTH_VALUE *)&(key.t.buffer[key.t.size]));
632 }
633 }
634 // if the HMAC key size is 0, a NULL string HMAC is allowed
635 if( key.t.size == 0
636 && s_inputAuthValues[sessionIndex].t.size == 0)
637 {
638 hmac->t.size = 0;
639 return;
640 }
641 // Start HMAC
642 hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
643 // Add cpHash
644 CryptUpdateDigest2B(&hmacState, &cpHash->b);
645 // Add nonceCaller
646 CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
647 // Add nonceTPM
648 CryptUpdateDigest2B(&hmacState, &session->nonceTPM.b);
649 // If needed, add nonceTPM for decrypt session
650 if(nonceDecrypt != NULL)
651 CryptUpdateDigest2B(&hmacState, &nonceDecrypt->b);
652 // If needed, add nonceTPM for encrypt session
653 if(nonceEncrypt != NULL)
654 CryptUpdateDigest2B(&hmacState, &nonceEncrypt->b);
655 // Add sessionAttributes
656 buffer = marshalBuffer;
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700657 bufferSize = sizeof(TPMA_SESSION);
Vadim Bendebury56797522015-05-20 10:32:25 -0700658 marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]),
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700659 &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -0700660 CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
661 // Complete the HMAC computation
662 CryptCompleteHMAC2B(&hmacState, &hmac->b);
663 return;
664}
665//
666//
667// CheckSessionHMAC()
668//
669// This function checks the HMAC of in a session. It uses ComputeCommandHMAC() to compute the
670// expected HMAC value and then compares the result with the HMAC in the authorization session. The
671// authorization is successful if they are the same.
672// If the authorizations are not the same, IncrementLockout() is called. It will return TPM_RC_AUTH_FAIL if
673// the failure caused the failureCount to increment. Otherwise, it will return TPM_RC_BAD_AUTH.
674//
675// Error Returns Meaning
676//
677// TPM_RC_AUTH_FAIL auth failure caused failureCount increment
678// TPM_RC_BAD_AUTH auth failure did not cause failureCount increment
679//
680static TPM_RC
681CheckSessionHMAC(
682 UINT32 sessionIndex, // IN: index of session to be processed
683 TPM2B_DIGEST *cpHash // IN: cpHash of the command
684 )
685{
686 TPM2B_DIGEST hmac; // authHMAC for comparing
687 // Compute authHMAC
688 ComputeCommandHMAC(sessionIndex, cpHash, &hmac);
689 // Compare the input HMAC with the authHMAC computed above.
690 if(!Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &hmac.b))
691 {
692 // If an HMAC session has a failure, invoke the anti-hammering
693 // if it applies to the authorized entity or the session.
694 // Otherwise, just indicate that the authorization is bad.
695 return IncrementLockout(sessionIndex);
696 }
697 return TPM_RC_SUCCESS;
698}
699//
700//
701// CheckPolicyAuthSession()
702//
703// This function is used to validate the authorization in a policy session. This function performs the following
704// comparisons to see if a policy authorization is properly provided. The check are:
705// a) compare policyDigest in session with authPolicy associated with the entity to be authorized;
706// b) compare timeout if applicable;
707// c) compare commandCode if applicable;
708//
709// d) compare cpHash if applicable; and
710// e) see if PCR values have changed since computed.
711// If all the above checks succeed, the handle is authorized. The order of these comparisons is not
712// important because any failure will result in the same error code.
713//
714// Error Returns Meaning
715//
716// TPM_RC_PCR_CHANGED PCR value is not current
717// TPM_RC_POLICY_FAIL policy session fails
718// TPM_RC_LOCALITY command locality is not allowed
719// TPM_RC_POLICY_CC CC doesn't match
720// TPM_RC_EXPIRED policy session has expired
721// TPM_RC_PP PP is required but not asserted
722// TPM_RC_NV_UNAVAILABLE NV is not available for write
723// TPM_RC_NV_RATE NV is rate limiting
724//
725static TPM_RC
726CheckPolicyAuthSession(
727 UINT32 sessionIndex, // IN: index of session to be processed
728 TPM_CC commandCode, // IN: command code
729 TPM2B_DIGEST *cpHash, // IN: cpHash using the algorithm of this
730 // session
731 TPM2B_DIGEST *nameHash // IN: nameHash using the session algorithm
732 )
733{
734 TPM_RC result = TPM_RC_SUCCESS;
735 SESSION *session;
736 TPM2B_DIGEST authPolicy;
737 TPMI_ALG_HASH policyAlg;
738 UINT8 locality;
739 // Initialize pointer to the auth session.
740 session = SessionGet(s_sessionHandles[sessionIndex]);
741 // If the command is TPM_RC_PolicySecret(), make sure that
742 // either password or authValue is required
743 if( commandCode == TPM_CC_PolicySecret
744 && session->attributes.isPasswordNeeded == CLEAR
745 && session->attributes.isAuthValueNeeded == CLEAR)
746 return TPM_RC_MODE;
747 // See if the PCR counter for the session is still valid.
748 if( !SessionPCRValueIsCurrent(s_sessionHandles[sessionIndex]) )
749 return TPM_RC_PCR_CHANGED;
750 // Get authPolicy.
751 policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex],
752 &authPolicy);
753 // Compare authPolicy.
754 if(!Memory2BEqual(&session->u2.policyDigest.b, &authPolicy.b))
755 return TPM_RC_POLICY_FAIL;
756 // Policy is OK so check if the other factors are correct
757 // Compare policy hash algorithm.
758 if(policyAlg != session->authHashAlg)
759 return TPM_RC_POLICY_FAIL;
760 // Compare timeout.
761 if(session->timeOut != 0)
762 {
763 // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE
764 // or TPM_RC_NV_RATE error may be returned here.
765 result = NvIsAvailable();
766 if(result != TPM_RC_SUCCESS)
767 return result;
768 if(session->timeOut < go.clock)
769 return TPM_RC_EXPIRED;
770 }
771 // If command code is provided it must match
772 if(session->commandCode != 0)
773 {
774 if(session->commandCode != commandCode)
775 return TPM_RC_POLICY_CC;
776 }
777 else
778 {
779 // If command requires a DUP or ADMIN authorization, the session must have
780 // command code set.
781 AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex);
782 if(role == AUTH_ADMIN || role == AUTH_DUP)
783 return TPM_RC_POLICY_FAIL;
784 }
785 // Check command locality.
786 {
787 BYTE sessionLocality[sizeof(TPMA_LOCALITY)];
788 BYTE *buffer = sessionLocality;
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700789 INT32 bufferSize = sizeof(TPMA_LOCALITY);
Vadim Bendebury56797522015-05-20 10:32:25 -0700790 // Get existing locality setting in canonical form
Jocelyn Bohr32be4042015-07-29 15:14:01 -0700791 TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -0700792 // See if the locality has been set
793 if(sessionLocality[0] != 0)
794 {
795 // If so, get the current locality
796 locality = _plat__LocalityGet();
797 if (locality < 5)
798 {
799 if( ((sessionLocality[0] & (1 << locality)) == 0)
800 || sessionLocality[0] > 31)
801 return TPM_RC_LOCALITY;
802 }
803 else if (locality > 31)
804 {
805 if(sessionLocality[0] != locality)
806 return TPM_RC_LOCALITY;
807 }
808 else
809 {
810 // Could throw an assert here but a locality error is just
811 // as good. It just means that, whatever the locality is, it isn't
812 // the locality requested so...
813 return TPM_RC_LOCALITY;
814 }
815 }
816 } // end of locality check
817 // Check physical presence.
818 if( session->attributes.isPPRequired == SET
819 && !_plat__PhysicalPresenceAsserted())
820 return TPM_RC_PP;
821 // Compare cpHash/nameHash if defined, or if the command requires an ADMIN or
822 // DUP role for this handle.
823 if(session->u1.cpHash.b.size != 0)
824 {
825 if(session->attributes.iscpHashDefined)
826 {
827 // Compare cpHash.
828 if(!Memory2BEqual(&session->u1.cpHash.b, &cpHash->b))
829 return TPM_RC_POLICY_FAIL;
830 }
831 else
832 {
833 // Compare nameHash.
834 // When cpHash is not defined, nameHash is placed in its space.
835 if(!Memory2BEqual(&session->u1.cpHash.b, &nameHash->b))
836 return TPM_RC_POLICY_FAIL;
837 }
838 }
839 if(session->attributes.checkNvWritten)
840 {
841 NV_INDEX nvIndex;
842 // If this is not an NV index, the policy makes no sense so fail it.
843 if(HandleGetType(s_associatedHandles[sessionIndex])!= TPM_HT_NV_INDEX)
844 return TPM_RC_POLICY_FAIL;
845 // Get the index data
846 NvGetIndexInfo(s_associatedHandles[sessionIndex], &nvIndex);
847 // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state
848 if( (nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
849 != (session->attributes.nvWrittenState == SET))
850 return TPM_RC_POLICY_FAIL;
851 }
852 return TPM_RC_SUCCESS;
853}
854//
855//
856// RetrieveSessionData()
857//
858// This function will unmarshal the sessions in the session area of a command. The values are placed in the
859// arrays that are defined at the beginning of this file. The normal unmarshaling errors are possible.
860//
861// Error Returns Meaning
862//
863// TPM_RC_SUCCSS unmarshaled without error
864// TPM_RC_SIZE the number of bytes unmarshaled is not the same as the value for
865// authorizationSize in the command
866//
867static TPM_RC
868RetrieveSessionData (
869 TPM_CC commandCode, // IN: command code
870 UINT32 *sessionCount, // OUT: number of sessions found
871 BYTE *sessionBuffer, // IN: pointer to the session buffer
872 INT32 bufferSize // IN: size of the session buffer
873 )
874{
875 int sessionIndex;
876 int i;
877 TPM_RC result;
878 SESSION *session;
879 TPM_HT sessionType;
880 s_decryptSessionIndex = UNDEFINED_INDEX;
881 s_encryptSessionIndex = UNDEFINED_INDEX;
882 s_auditSessionIndex = UNDEFINED_INDEX;
883 for(sessionIndex = 0; bufferSize > 0; sessionIndex++)
884 {
885 // If maximum allowed number of sessions has been parsed, return a size
886 // error with a session number that is larger than the number of allowed
887 // sessions
888 if(sessionIndex == MAX_SESSION_NUM)
889 return TPM_RC_SIZE + TPM_RC_S + g_rcIndex[sessionIndex+1];
890 // make sure that the associated handle for each session starts out
891 // unassigned
892 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
893 // First parameter: Session handle.
894 result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex],
ChromeOS Developere85c65b2015-07-10 10:12:43 -0700895 &sessionBuffer, &bufferSize, TRUE);
Vadim Bendebury56797522015-05-20 10:32:25 -0700896 if(result != TPM_RC_SUCCESS)
897 return result + TPM_RC_S + g_rcIndex[sessionIndex];
898 // Second parameter: Nonce.
899 result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex],
900 &sessionBuffer, &bufferSize);
901 if(result != TPM_RC_SUCCESS)
902 return result + TPM_RC_S + g_rcIndex[sessionIndex];
903 // Third parameter: sessionAttributes.
904 result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex],
905 &sessionBuffer, &bufferSize);
906 if(result != TPM_RC_SUCCESS)
907 return result + TPM_RC_S + g_rcIndex[sessionIndex];
908 // Fourth parameter: authValue (PW or HMAC).
909 result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex],
910 &sessionBuffer, &bufferSize);
911 if(result != TPM_RC_SUCCESS)
912 return result + TPM_RC_S + g_rcIndex[sessionIndex];
913 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
914 {
915 // A PWAP session needs additional processing.
916 // Can't have any attributes set other than continueSession bit
917 if( s_attributes[sessionIndex].encrypt
918 || s_attributes[sessionIndex].decrypt
919 || s_attributes[sessionIndex].audit
920 || s_attributes[sessionIndex].auditExclusive
921 || s_attributes[sessionIndex].auditReset
922 )
923 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
924 // The nonce size must be zero.
925 if(s_nonceCaller[sessionIndex].t.size != 0)
926 return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex];
927 continue;
928 }
929 // For not password sessions...
930 // Find out if the session is loaded.
931 if(!SessionIsLoaded(s_sessionHandles[sessionIndex]))
932 return TPM_RC_REFERENCE_S0 + sessionIndex;
933 sessionType = HandleGetType(s_sessionHandles[sessionIndex]);
934 session = SessionGet(s_sessionHandles[sessionIndex]);
935 // Check if the session is an HMAC/policy session.
936 if( ( session->attributes.isPolicy == SET
937 && sessionType == TPM_HT_HMAC_SESSION
938 )
939 || ( session->attributes.isPolicy == CLEAR
940 && sessionType == TPM_HT_POLICY_SESSION
941 )
942 )
943 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
944 // Check that this handle has not previously been used.
945 for(i = 0; i < sessionIndex; i++)
946 {
947 if(s_sessionHandles[i] == s_sessionHandles[sessionIndex])
948 return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex];
949 }
950 // If the session is used for parameter encryption or audit as well, set
951 // the corresponding indices.
952 // First process decrypt.
953 if(s_attributes[sessionIndex].decrypt)
954 {
955 // Check if the commandCode allows command parameter encryption.
956 if(DecryptSize(commandCode) == 0)
957 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
958 // Encrypt attribute can only appear in one session
959 if(s_decryptSessionIndex != UNDEFINED_INDEX)
960 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
961 // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL
962 if(session->symmetric.algorithm == TPM_ALG_NULL)
963 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
964 // All checks passed, so set the index for the session used to decrypt
965 // a command parameter.
966 s_decryptSessionIndex = sessionIndex;
967 }
968 // Now process encrypt.
969 if(s_attributes[sessionIndex].encrypt)
970 {
971 // Check if the commandCode allows response parameter encryption.
972 if(EncryptSize(commandCode) == 0)
973 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
974 // Encrypt attribute can only appear in one session.
975 if(s_encryptSessionIndex != UNDEFINED_INDEX)
976 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
977 // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL
978 if(session->symmetric.algorithm == TPM_ALG_NULL)
979 return TPM_RC_SYMMETRIC + TPM_RC_S + g_rcIndex[sessionIndex];
980 // All checks passed, so set the index for the session used to encrypt
981 // a response parameter.
982 s_encryptSessionIndex = sessionIndex;
983 }
984 // At last process audit.
985 if(s_attributes[sessionIndex].audit)
986 {
987 // Audit attribute can only appear in one session.
988 if(s_auditSessionIndex != UNDEFINED_INDEX)
989 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
990 // An audit session can not be policy session.
991 if( HandleGetType(s_sessionHandles[sessionIndex])
992 == TPM_HT_POLICY_SESSION)
993 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
994 // If this is a reset of the audit session, or the first use
995 // of the session as an audit session, it doesn't matter what
996 // the exclusive state is. The session will become exclusive.
997 if( s_attributes[sessionIndex].auditReset == CLEAR
998 && session->attributes.isAudit == SET)
999 {
1000 // Not first use or reset. If auditExlusive is SET, then this
1001 // session must be the current exclusive session.
1002 if( s_attributes[sessionIndex].auditExclusive == SET
1003 && g_exclusiveAuditSession != s_sessionHandles[sessionIndex])
1004 return TPM_RC_EXCLUSIVE;
1005 }
1006 s_auditSessionIndex = sessionIndex;
1007 }
1008 // Initialize associated handle as undefined. This will be changed when
1009 // the handles are processed.
1010 s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED;
1011 }
1012 // Set the number of sessions found.
1013 *sessionCount = sessionIndex;
1014 return TPM_RC_SUCCESS;
1015}
1016//
1017//
1018// CheckLockedOut()
1019//
1020// This function checks to see if the TPM is in lockout. This function should only be called if the entity being
1021// checked is subject to DA protection. The TPM is in lockout if the NV is not available and a DA write is
1022// pending. Otherwise the TPM is locked out if checking for lockoutAuth (lockoutAuthCheck == TRUE) and
1023// use of lockoutAuth is disabled, or failedTries >= maxTries
1024//
1025// Error Returns Meaning
1026//
1027// TPM_RC_NV_RATE NV is rate limiting
1028// TPM_RC_NV_UNAVAILABLE NV is not available at this time
1029// TPM_RC_LOCKOUT TPM is in lockout
1030//
1031static TPM_RC
1032CheckLockedOut(
1033 BOOL lockoutAuthCheck // IN: TRUE if checking is for lockoutAuth
1034 )
1035{
1036 TPM_RC result;
1037 // If NV is unavailable, and current cycle state recorded in NV is not
1038 // SHUTDOWN_NONE, refuse to check any authorization because we would
1039 // not be able to handle a DA failure.
1040 result = NvIsAvailable();
1041 if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE)
1042 return result;
1043 // Check if DA info needs to be updated in NV.
1044 if(s_DAPendingOnNV)
1045 {
1046 // If NV is accessible, ...
1047 if(result == TPM_RC_SUCCESS)
1048 {
1049 // ... write the pending DA data and proceed.
1050 NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED,
1051 &gp.lockOutAuthEnabled);
1052 NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries);
1053 g_updateNV = TRUE;
1054 s_DAPendingOnNV = FALSE;
1055 }
1056 else
1057 {
1058 // Otherwise no authorization can be checked.
1059 return result;
1060 }
1061 }
1062 // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth
1063 // is disabled...
1064 if(lockoutAuthCheck)
1065 {
1066 if(gp.lockOutAuthEnabled == FALSE)
1067 return TPM_RC_LOCKOUT;
1068 }
1069 else
1070 {
1071 // ... or if the number of failed tries has been maxed out.
1072 if(gp.failedTries >= gp.maxTries)
1073 return TPM_RC_LOCKOUT;
1074 }
1075 return TPM_RC_SUCCESS;
1076}
1077//
1078//
1079// CheckAuthSession()
1080//
1081// This function checks that the authorization session properly authorizes the use of the associated handle.
1082//
1083// Error Returns Meaning
1084//
1085// TPM_RC_LOCKOUT entity is protected by DA and TPM is in lockout, or TPM is locked out
1086// on NV update pending on DA parameters
1087// TPM_RC_PP Physical Presence is required but not provided
1088// TPM_RC_AUTH_FAIL HMAC or PW authorization failed with DA side-effects (can be a
1089// policy session)
1090// TPM_RC_BAD_AUTH HMAC or PW authorization failed without DA side-effects (can be a
1091// policy session)
1092// TPM_RC_POLICY_FAIL if policy session fails
1093// TPM_RC_POLICY_CC command code of policy was wrong
1094// TPM_RC_EXPIRED the policy session has expired
1095// TPM_RC_PCR ???
1096// TPM_RC_AUTH_UNAVAILABLE authValue or authPolicy unavailable
1097//
1098static TPM_RC
1099CheckAuthSession(
1100 TPM_CC commandCode, // IN: commandCode
1101 UINT32 sessionIndex, // IN: index of session to be processed
1102 TPM2B_DIGEST *cpHash, // IN: cpHash
1103 TPM2B_DIGEST *nameHash // IN: nameHash
1104//
1105 )
1106{
1107 TPM_RC result;
1108 SESSION *session = NULL;
1109 TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex];
1110 TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex];
1111 TPM_HT sessionHandleType = HandleGetType(sessionHandle);
1112 pAssert(sessionHandle != TPM_RH_UNASSIGNED);
1113 if(sessionHandle != TPM_RS_PW)
1114 session = SessionGet(sessionHandle);
1115 pAssert(sessionHandleType != TPM_HT_POLICY_SESSION || session != NULL);
1116 // If the authorization session is not a policy session, or if the policy
1117 // session requires authorization, then check lockout.
1118 if( sessionHandleType != TPM_HT_POLICY_SESSION
1119 || session->attributes.isAuthValueNeeded
1120 || session->attributes.isPasswordNeeded)
1121 {
1122 // See if entity is subject to lockout.
1123 if(!IsDAExempted(associatedHandle))
1124 {
1125 // If NV is unavailable, and current cycle state recorded in NV is not
1126 // SHUTDOWN_NONE, refuse to check any authorization because we would
1127 // not be able to handle a DA failure.
1128 result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT);
1129 if(result != TPM_RC_SUCCESS)
1130 return result;
1131 }
1132 }
1133 if(associatedHandle == TPM_RH_PLATFORM)
1134 {
1135 // If the physical presence is required for this command, check for PP
1136 // assertion. If it isn't asserted, no point going any further.
1137 if( PhysicalPresenceIsRequired(commandCode)
1138 && !_plat__PhysicalPresenceAsserted()
1139 )
1140 return TPM_RC_PP;
1141 }
1142 // If a policy session is required, make sure that it is being used.
1143 if( IsPolicySessionRequired(commandCode, sessionIndex)
1144 && sessionHandleType != TPM_HT_POLICY_SESSION)
1145 return TPM_RC_AUTH_TYPE;
1146 // If this is a PW authorization, check it and return.
1147 if(sessionHandle == TPM_RS_PW)
1148 {
1149 if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1150 return CheckPWAuthSession(sessionIndex);
1151 else
1152 return TPM_RC_AUTH_UNAVAILABLE;
1153 }
1154 // If this is a policy session, ...
1155 if(sessionHandleType == TPM_HT_POLICY_SESSION)
1156 {
1157 // ... see if the entity has a policy, ...
1158 if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex))
1159 return TPM_RC_AUTH_UNAVAILABLE;
1160 // ... and check the policy session.
1161 result = CheckPolicyAuthSession(sessionIndex, commandCode,
1162 cpHash, nameHash);
1163 if (result != TPM_RC_SUCCESS)
1164 return result;
1165 }
1166 else
1167 {
1168 // For non policy, the entity being accessed must allow authorization
1169 // with an auth value. This is required even if the auth value is not
1170 // going to be used in an HMAC because it is bound.
1171 if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex))
1172 return TPM_RC_AUTH_UNAVAILABLE;
1173 }
1174 // At this point, the session must be either a policy or an HMAC session.
1175 session = SessionGet(s_sessionHandles[sessionIndex]);
1176 if( sessionHandleType == TPM_HT_POLICY_SESSION
1177 && session->attributes.isPasswordNeeded == SET)
1178 {
1179 // For policy session that requires a password, check it as PWAP session.
1180 return CheckPWAuthSession(sessionIndex);
1181 }
1182 else
1183 {
1184 // For other policy or HMAC sessions, have its HMAC checked.
1185 return CheckSessionHMAC(sessionIndex, cpHash);
1186 }
1187}
1188#ifdef TPM_CC_GetCommandAuditDigest
1189//
1190//
1191// CheckCommandAudit()
1192//
1193// This function checks if the current command may trigger command audit, and if it is safe to perform the
1194// action.
1195//
1196// Error Returns Meaning
1197//
1198// TPM_RC_NV_UNAVAILABLE NV is not available for write
1199// TPM_RC_NV_RATE NV is rate limiting
1200//
1201static TPM_RC
1202CheckCommandAudit(
1203 TPM_CC commandCode, // IN: Command code
1204 UINT32 handleNum, // IN: number of element in handle array
1205 TPM_HANDLE handles[], // IN: array of handle
1206 BYTE *parmBufferStart, // IN: start of parameter buffer
1207 UINT32 parmBufferSize // IN: size of parameter buffer
1208 )
1209{
1210 TPM_RC result = TPM_RC_SUCCESS;
1211 // If audit is implemented, need to check to see if auditing is being done
1212 // for this command.
1213 if(CommandAuditIsRequired(commandCode))
1214 {
1215 // If the audit digest is clear and command audit is required, NV must be
1216 // available so that TPM2_GetCommandAuditDigest() is able to increment
1217 // audit counter. If NV is not available, the function bails out to prevent
1218 // the TPM from attempting an operation that would fail anyway.
1219 if( gr.commandAuditDigest.t.size == 0
1220 || commandCode == TPM_CC_GetCommandAuditDigest)
1221 {
1222 result = NvIsAvailable();
1223 if(result != TPM_RC_SUCCESS)
1224 return result;
1225 }
1226 ComputeCpHash(gp.auditHashAlg, commandCode, handleNum,
1227 handles, parmBufferSize, parmBufferStart,
1228 &s_cpHashForCommandAudit, NULL);
1229 }
1230 return TPM_RC_SUCCESS;
1231}
1232#endif
1233//
1234//
1235// ParseSessionBuffer()
1236//
1237// This function is the entry function for command session processing. It iterates sessions in session area
1238// and reports if the required authorization has been properly provided. It also processes audit session and
1239// passes the information of encryption sessions to parameter encryption module.
1240//
1241// Error Returns Meaning
1242//
1243// various parsing failure or authorization failure
1244//
1245TPM_RC
1246ParseSessionBuffer(
1247 TPM_CC commandCode, // IN: Command code
1248 UINT32 handleNum, // IN: number of element in handle array
1249 TPM_HANDLE handles[], // IN: array of handle
1250 BYTE *sessionBufferStart, // IN: start of session buffer
1251 UINT32 sessionBufferSize, // IN: size of session buffer
1252 BYTE *parmBufferStart, // IN: start of parameter buffer
1253 UINT32 parmBufferSize // IN: size of parameter buffer
1254 )
1255{
1256 TPM_RC result;
1257 UINT32 i;
1258 INT32 size = 0;
1259 TPM2B_AUTH extraKey;
1260 UINT32 sessionIndex;
1261 SESSION *session;
1262 TPM2B_DIGEST cpHash;
1263 TPM2B_DIGEST nameHash;
1264 TPM_ALG_ID cpHashAlg = TPM_ALG_NULL; // algID for the last computed
1265 // cpHash
1266 // Check if a command allows any session in its session area.
1267 if(!IsSessionAllowed(commandCode))
1268 return TPM_RC_AUTH_CONTEXT;
1269 // Default-initialization.
1270 s_sessionNum = 0;
1271 cpHash.t.size = 0;
1272 result = RetrieveSessionData(commandCode, &s_sessionNum,
1273 sessionBufferStart, sessionBufferSize);
1274 if(result != TPM_RC_SUCCESS)
1275 return result;
1276 // There is no command in the TPM spec that has more handles than
1277 // MAX_SESSION_NUM.
1278 pAssert(handleNum <= MAX_SESSION_NUM);
1279 // Associate the session with an authorization handle.
1280 for(i = 0; i < handleNum; i++)
1281 {
1282 if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1283 {
1284 // If the received session number is less than the number of handle
1285 // that requires authorization, an error should be returned.
1286 // Note: for all the TPM 2.0 commands, handles requiring
1287 // authorization come first in a command input.
1288 if(i > (s_sessionNum - 1))
1289 return TPM_RC_AUTH_MISSING;
1290 // Record the handle associated with the authorization session
1291 s_associatedHandles[i] = handles[i];
1292 }
1293 }
1294 // Consistency checks are done first to avoid auth failure when the command
1295 // will not be executed anyway.
1296 for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++)
1297 {
1298 // PW session must be an authorization session
1299 if(s_sessionHandles[sessionIndex] == TPM_RS_PW )
1300 {
1301 if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED)
1302 return TPM_RC_HANDLE + g_rcIndex[sessionIndex];
1303 }
1304 else
1305 {
1306 session = SessionGet(s_sessionHandles[sessionIndex]);
1307 // A trial session can not appear in session area, because it cannot
1308 // be used for authorization, audit or encrypt/decrypt.
1309 if(session->attributes.isTrialPolicy == SET)
1310 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1311 // See if the session is bound to a DA protected entity
1312 // NOTE: Since a policy session is never bound, a policy is still
1313 // usable even if the object is DA protected and the TPM is in
1314 // lockout.
1315 if(session->attributes.isDaBound == SET)
1316 {
1317 result = CheckLockedOut(session->attributes.isLockoutBound == SET);
1318 if(result != TPM_RC_SUCCESS)
1319 return result;
1320 }
1321 // If the current cpHash is the right one, don't re-compute.
1322 if(cpHashAlg != session->authHashAlg) // different so compute
1323 {
1324 cpHashAlg = session->authHashAlg; // save this new algID
1325 ComputeCpHash(session->authHashAlg, commandCode, handleNum,
1326 handles, parmBufferSize, parmBufferStart,
1327 &cpHash, &nameHash);
1328 }
1329 // If this session is for auditing, save the cpHash.
1330 if(s_attributes[sessionIndex].audit)
1331 s_cpHashForAudit = cpHash;
1332 }
1333 // if the session has an associated handle, check the auth
1334 if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED)
1335 {
1336 result = CheckAuthSession(commandCode, sessionIndex,
1337 &cpHash, &nameHash);
1338 if(result != TPM_RC_SUCCESS)
1339 return RcSafeAddToResult(result,
1340 TPM_RC_S + g_rcIndex[sessionIndex]);
1341 }
1342 else
1343 {
1344 // a session that is not for authorization must either be encrypt,
1345 // decrypt, or audit
1346 if( s_attributes[sessionIndex].audit == CLEAR
1347 && s_attributes[sessionIndex].encrypt == CLEAR
1348 && s_attributes[sessionIndex].decrypt == CLEAR)
1349 return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex];
1350 // check HMAC for encrypt/decrypt/audit only sessions
1351 result = CheckSessionHMAC(sessionIndex, &cpHash);
1352 if(result != TPM_RC_SUCCESS)
1353 return RcSafeAddToResult(result,
1354 TPM_RC_S + g_rcIndex[sessionIndex]);
1355 }
1356 }
1357#ifdef TPM_CC_GetCommandAuditDigest
1358 // Check if the command should be audited.
1359 result = CheckCommandAudit(commandCode, handleNum, handles,
1360 parmBufferStart, parmBufferSize);
1361 if(result != TPM_RC_SUCCESS)
1362 return result; // No session number to reference
1363#endif
1364 // Decrypt the first parameter if applicable. This should be the last operation
1365 // in session processing.
1366 // If the encrypt session is associated with a handle and the handle's
1367 // authValue is available, then authValue is concatenated with sessionAuth to
1368 // generate encryption key, no matter if the handle is the session bound entity
1369 // or not.
1370 if(s_decryptSessionIndex != UNDEFINED_INDEX)
1371 {
1372 // Get size of the leading size field in decrypt parameter
1373 if( s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED
1374 && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex],
1375 commandCode,
1376 s_decryptSessionIndex)
1377 )
1378 {
1379 extraKey.b.size=
1380 EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex],
1381 &extraKey.t.buffer);
1382 }
1383 else
1384 {
1385 extraKey.b.size = 0;
1386 }
1387 size = DecryptSize(commandCode);
1388 result = CryptParameterDecryption(
1389 s_sessionHandles[s_decryptSessionIndex],
1390 &s_nonceCaller[s_decryptSessionIndex].b,
1391 parmBufferSize, (UINT16)size,
1392 &extraKey,
1393 parmBufferStart);
1394 if(result != TPM_RC_SUCCESS)
1395 return RcSafeAddToResult(result,
1396 TPM_RC_S + g_rcIndex[s_decryptSessionIndex]);
1397 }
1398 return TPM_RC_SUCCESS;
1399}
1400//
1401//
1402// CheckAuthNoSession()
1403//
1404// Function to process a command with no session associated. The function makes sure all the handles in
1405// the command require no authorization.
1406//
1407//
1408//
1409// Error Returns Meaning
1410//
1411// TPM_RC_AUTH_MISSING failure - one or more handles require auth
1412//
1413TPM_RC
1414CheckAuthNoSession(
1415 TPM_CC commandCode, // IN: Command Code
1416 UINT32 handleNum, // IN: number of handles in command
1417 TPM_HANDLE handles[], // IN: array of handle
1418 BYTE *parmBufferStart, // IN: start of parameter buffer
1419 UINT32 parmBufferSize // IN: size of parameter buffer
1420 )
1421{
1422 UINT32 i;
1423 TPM_RC result = TPM_RC_SUCCESS;
1424 // Check if the commandCode requires authorization
1425 for(i = 0; i < handleNum; i++)
1426 {
1427 if(CommandAuthRole(commandCode, i) != AUTH_NONE)
1428 return TPM_RC_AUTH_MISSING;
1429 }
1430#ifdef TPM_CC_GetCommandAuditDigest
1431 // Check if the command should be audited.
1432 result = CheckCommandAudit(commandCode, handleNum, handles,
1433 parmBufferStart, parmBufferSize);
1434 if(result != TPM_RC_SUCCESS) return result;
1435#endif
1436 // Initialize number of sessions to be 0
1437 s_sessionNum = 0;
1438 return TPM_RC_SUCCESS;
1439}
1440//
1441//
1442// Response Session Processing
1443//
1444// Introduction
1445//
1446// The following functions build the session area in a response, and handle the audit sessions (if present).
1447//
1448// ComputeRpHash()
1449//
1450// Function to compute rpHash (Response Parameter Hash). The rpHash is only computed if there is an
1451// HMAC authorization session and the return code is TPM_RC_SUCCESS.
1452//
1453static void
1454ComputeRpHash(
1455 TPM_ALG_ID hashAlg, // IN: hash algorithm to compute rpHash
1456 TPM_CC commandCode, // IN: commandCode
1457 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1458 BYTE *resParmBuffer, // IN: response parameter buffer
1459 TPM2B_DIGEST *rpHash // OUT: rpHash
1460 )
1461{
1462 // The command result in rpHash is always TPM_RC_SUCCESS.
1463 TPM_RC responseCode = TPM_RC_SUCCESS;
1464 HASH_STATE hashState;
1465 // rpHash := hash(responseCode || commandCode || parameters)
1466 // Initiate hash creation.
1467 rpHash->t.size = CryptStartHash(hashAlg, &hashState);
1468 // Add hash constituents.
1469 CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode);
1470 CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode);
1471 CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer);
1472 // Complete hash computation.
1473 CryptCompleteHash2B(&hashState, &rpHash->b);
1474 return;
1475}
1476//
1477//
1478// InitAuditSession()
1479//
1480// This function initializes the audit data in an audit session.
1481//
1482static void
1483InitAuditSession(
1484 SESSION *session // session to be initialized
1485 )
1486{
1487 // Mark session as an audit session.
1488 session->attributes.isAudit = SET;
1489 // Audit session can not be bound.
1490 session->attributes.isBound = CLEAR;
1491 // Size of the audit log is the size of session hash algorithm digest.
1492 session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg);
1493 // Set the original digest value to be 0.
1494 MemorySet(&session->u2.auditDigest.t.buffer,
1495 0,
1496 session->u2.auditDigest.t.size);
1497 return;
1498}
1499//
1500//
1501// Audit()
1502//
1503// This function updates the audit digest in an audit session.
1504//
1505static void
1506Audit(
1507 SESSION *auditSession, // IN: loaded audit session
1508 TPM_CC commandCode, // IN: commandCode
1509 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1510 BYTE *resParmBuffer // IN: response parameter buffer
1511 )
1512{
1513 TPM2B_DIGEST rpHash; // rpHash for response
1514 HASH_STATE hashState;
1515 // Compute rpHash
1516 ComputeRpHash(auditSession->authHashAlg,
1517 commandCode,
1518 resParmBufferSize,
1519 resParmBuffer,
1520 &rpHash);
1521 // auditDigestnew := hash (auditDigestold || cpHash || rpHash)
1522 // Start hash computation.
1523 CryptStartHash(auditSession->authHashAlg, &hashState);
1524 // Add old digest.
1525 CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b);
1526 // Add cpHash and rpHash.
1527 CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b);
1528 CryptUpdateDigest2B(&hashState, &rpHash.b);
1529 // Finalize the hash.
1530 CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b);
1531 return;
1532}
1533#ifdef TPM_CC_GetCommandAuditDigest
1534//
1535//
1536// CommandAudit()
1537//
1538// This function updates the command audit digest.
1539//
1540static void
1541CommandAudit(
1542 TPM_CC commandCode, // IN: commandCode
1543 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1544 BYTE *resParmBuffer // IN: response parameter buffer
1545 )
1546{
1547 if(CommandAuditIsRequired(commandCode))
1548 {
1549 TPM2B_DIGEST rpHash; // rpHash for response
1550 HASH_STATE hashState;
1551 // Compute rpHash.
1552 ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize,
1553 resParmBuffer, &rpHash);
1554 // If the digest.size is one, it indicates the special case of changing
1555 // the audit hash algorithm. For this case, no audit is done on exit.
1556 // NOTE: When the hash algorithm is changed, g_updateNV is set in order to
1557 // force an update to the NV on exit so that the change in digest will
1558 // be recorded. So, it is safe to exit here without setting any flags
1559 // because the digest change will be written to NV when this code exits.
1560 if(gr.commandAuditDigest.t.size == 1)
1561 {
1562 gr.commandAuditDigest.t.size = 0;
1563 return;
1564 }
1565 // If the digest size is zero, need to start a new digest and increment
1566 // the audit counter.
1567 if(gr.commandAuditDigest.t.size == 0)
1568 {
1569 gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg);
1570 MemorySet(gr.commandAuditDigest.t.buffer,
1571 0,
1572 gr.commandAuditDigest.t.size);
1573 // Bump the counter and save its value to NV.
1574 gp.auditCounter++;
1575 NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
1576 g_updateNV = TRUE;
1577//
1578 }
1579 // auditDigestnew := hash (auditDigestold || cpHash || rpHash)
1580 // Start hash computation.
1581 CryptStartHash(gp.auditHashAlg, &hashState);
1582 // Add old digest.
1583 CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b);
1584 // Add cpHash
1585 CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b);
1586 // Add rpHash
1587 CryptUpdateDigest2B(&hashState, &rpHash.b);
1588 // Finalize the hash.
1589 CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b);
1590 }
1591 return;
1592}
1593#endif
1594//
1595//
1596// UpdateAuditSessionStatus()
1597//
1598// Function to update the internal audit related states of a session. It
1599// a) initializes the session as audit session and sets it to be exclusive if this is the first time it is used for
1600// audit or audit reset was requested;
1601// b) reports exclusive audit session;
1602// c) extends audit log; and
1603// d) clears exclusive audit session if no audit session found in the command.
1604//
1605static void
1606UpdateAuditSessionStatus(
1607 TPM_CC commandCode, // IN: commandCode
1608 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1609 BYTE *resParmBuffer // IN: response parameter buffer
1610 )
1611{
1612 UINT32 i;
1613 TPM_HANDLE auditSession = TPM_RH_UNASSIGNED;
1614 // Iterate through sessions
1615 for (i = 0; i < s_sessionNum; i++)
1616 {
1617 SESSION *session;
1618 // PW session do not have a loaded session and can not be an audit
1619 // session either. Skip it.
1620 if(s_sessionHandles[i] == TPM_RS_PW) continue;
1621 session = SessionGet(s_sessionHandles[i]);
1622 // If a session is used for audit
1623 if(s_attributes[i].audit == SET)
1624 {
1625 // An audit session has been found
1626 auditSession = s_sessionHandles[i];
1627 // If the session has not been an audit session yet, or
1628 // the auditSetting bits indicate a reset, initialize it and set
1629 // it to be the exclusive session
1630 if( session->attributes.isAudit == CLEAR
1631 || s_attributes[i].auditReset == SET
1632 )
1633 {
1634 InitAuditSession(session);
1635 g_exclusiveAuditSession = auditSession;
1636 }
1637 else
1638 {
1639 // Check if the audit session is the current exclusive audit
1640 // session and, if not, clear previous exclusive audit session.
1641 if(g_exclusiveAuditSession != auditSession)
1642 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1643 }
1644 // Report audit session exclusivity.
1645 if(g_exclusiveAuditSession == auditSession)
1646 {
1647 s_attributes[i].auditExclusive = SET;
1648 }
1649 else
1650 {
1651 s_attributes[i].auditExclusive = CLEAR;
1652 }
1653 // Extend audit log.
1654 Audit(session, commandCode, resParmBufferSize, resParmBuffer);
1655 }
1656 }
1657 // If no audit session is found in the command, and the command allows
1658 // a session then, clear the current exclusive
1659 // audit session.
1660 if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode))
1661 {
1662 g_exclusiveAuditSession = TPM_RH_UNASSIGNED;
1663 }
1664 return;
1665}
1666//
1667//
1668// ComputeResponseHMAC()
1669//
1670// Function to compute HMAC for authorization session in a response.
1671//
1672static void
1673ComputeResponseHMAC(
1674 UINT32 sessionIndex, // IN: session index to be processed
1675 SESSION *session, // IN: loaded session
1676 TPM_CC commandCode, // IN: commandCode
1677 TPM2B_NONCE *nonceTPM, // IN: nonceTPM
1678 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1679 BYTE *resParmBuffer, // IN: response parameter buffer
1680 TPM2B_DIGEST *hmac // OUT: authHMAC
1681 )
1682{
1683 TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2));
1684 TPM2B_KEY key; // HMAC key
1685 BYTE marshalBuffer[sizeof(TPMA_SESSION)];
1686 BYTE *buffer;
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001687 INT32 bufferSize;
Vadim Bendebury56797522015-05-20 10:32:25 -07001688 UINT32 marshalSize;
1689 HMAC_STATE hmacState;
1690 TPM2B_DIGEST rp_hash;
1691//
1692 // Compute rpHash.
1693 ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize,
1694 resParmBuffer, &rp_hash);
1695 // Generate HMAC key
1696 MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer));
1697 // Check if the session has an associated handle and the associated entity is
1698 // the one that the session is bound to.
1699 // If not bound, add the authValue of this entity to the HMAC key.
1700 if( s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED
1701 && !( HandleGetType(s_sessionHandles[sessionIndex])
1702 == TPM_HT_POLICY_SESSION
1703 && session->attributes.isAuthValueNeeded == CLEAR)
1704 && !session->attributes.requestWasBound)
1705 {
1706 pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer));
1707 key.t.size = key.t.size +
1708 EntityGetAuthValue(s_associatedHandles[sessionIndex],
1709 (AUTH_VALUE *)&key.t.buffer[key.t.size]);
1710 }
1711 // if the HMAC key size for a policy session is 0, the response HMAC is
1712 // computed according to the input HMAC
1713 if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1714 && key.t.size == 0
1715 && s_inputAuthValues[sessionIndex].t.size == 0)
1716 {
1717 hmac->t.size = 0;
1718 return;
1719 }
1720 // Start HMAC computation.
1721 hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState);
1722 // Add hash components.
1723 CryptUpdateDigest2B(&hmacState, &rp_hash.b);
1724 CryptUpdateDigest2B(&hmacState, &nonceTPM->b);
1725 CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b);
1726 // Add session attributes.
1727 buffer = marshalBuffer;
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001728 bufferSize = sizeof(TPMA_SESSION);
1729 marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -07001730 CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer);
1731 // Finalize HMAC.
1732 CryptCompleteHMAC2B(&hmacState, &hmac->b);
1733 return;
1734}
1735//
1736//
1737// BuildSingleResponseAuth()
1738//
1739// Function to compute response for an authorization session.
1740//
1741static void
1742BuildSingleResponseAuth(
1743 UINT32 sessionIndex, // IN: session index to be processed
1744 TPM_CC commandCode, // IN: commandCode
1745 UINT32 resParmBufferSize, // IN: size of response parameter buffer
1746 BYTE *resParmBuffer, // IN: response parameter buffer
1747 TPM2B_AUTH *auth // OUT: authHMAC
1748 )
1749//
1750{
1751 // For password authorization, field is empty.
1752 if(s_sessionHandles[sessionIndex] == TPM_RS_PW)
1753 {
1754 auth->t.size = 0;
1755 }
1756 else
1757 {
1758 // Fill in policy/HMAC based session response.
1759 SESSION *session = SessionGet(s_sessionHandles[sessionIndex]);
1760 // If the session is a policy session with isPasswordNeeded SET, the auth
1761 // field is empty.
1762 if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION
1763 && session->attributes.isPasswordNeeded == SET)
1764 auth->t.size = 0;
1765 else
1766 // Compute response HMAC.
1767 ComputeResponseHMAC(sessionIndex,
1768 session,
1769 commandCode,
1770 &session->nonceTPM,
1771 resParmBufferSize,
1772 resParmBuffer,
1773 auth);
1774 }
1775 return;
1776}
1777//
1778//
1779// UpdateTPMNonce()
1780//
1781// Updates TPM nonce in both internal session or response if applicable.
1782//
1783static void
1784UpdateTPMNonce(
1785 UINT16 noncesSize, // IN: number of elements in 'nonces' array
1786 TPM2B_NONCE nonces[] // OUT: nonceTPM
1787 )
1788{
1789 UINT32 i;
1790 pAssert(noncesSize >= s_sessionNum);
1791 for(i = 0; i < s_sessionNum; i++)
1792 {
1793 SESSION *session;
1794 // For PW session, nonce is 0.
1795 if(s_sessionHandles[i] == TPM_RS_PW)
1796 {
1797 nonces[i].t.size = 0;
1798 continue;
1799 }
1800 session = SessionGet(s_sessionHandles[i]);
1801 // Update nonceTPM in both internal session and response.
1802 CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer);
1803 nonces[i] = session->nonceTPM;
1804 }
1805 return;
1806}
1807//
1808//
1809// UpdateInternalSession()
1810//
1811// Updates internal sessions:
1812//
1813//
1814// a) Restarts session time, and
1815// b) Clears a policy session since nonce is rolling.
1816//
1817static void
1818UpdateInternalSession(
1819 void
1820 )
1821{
1822 UINT32 i;
1823 for(i = 0; i < s_sessionNum; i++)
1824 {
1825 // For PW session, no update.
1826 if(s_sessionHandles[i] == TPM_RS_PW) continue;
1827 if(s_attributes[i].continueSession == CLEAR)
1828 {
1829 // Close internal session.
1830 SessionFlush(s_sessionHandles[i]);
1831 }
1832 else
1833 {
1834 // If nonce is rolling in a policy session, the policy related data
1835 // will be re-initialized.
1836 if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION)
1837 {
1838 SESSION *session = SessionGet(s_sessionHandles[i]);
1839 // When the nonce rolls it starts a new timing interval for the
1840 // policy session.
1841 SessionResetPolicyData(session);
1842 session->startTime = go.clock;
1843 }
1844 }
1845 }
1846 return;
1847}
1848//
1849//
1850// BuildResponseSession()
1851//
1852// Function to build Session buffer in a response.
1853//
1854void
1855BuildResponseSession(
1856 TPM_ST tag, // IN: tag
1857 TPM_CC commandCode, // IN: commandCode
1858 UINT32 resHandleSize, // IN: size of response handle buffer
1859 UINT32 resParmSize, // IN: size of response parameter buffer
1860 UINT32 *resSessionSize // OUT: response session area
1861 )
1862{
1863 BYTE *resParmBuffer;
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001864 INT32 bufferSize;
Vadim Bendebury56797522015-05-20 10:32:25 -07001865 TPM2B_NONCE responseNonces[MAX_SESSION_NUM];
1866 // Compute response parameter buffer start.
1867 resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) +
1868 sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize;
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001869 bufferSize = MAX_RESPONSE_SIZE - sizeof(TPM_ST) - sizeof(UINT32) -
1870 sizeof(TPM_RC) - resHandleSize;
Vadim Bendebury56797522015-05-20 10:32:25 -07001871 // For TPM_ST_SESSIONS, there is parameterSize field.
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001872 if(tag == TPM_ST_SESSIONS) {
Vadim Bendebury56797522015-05-20 10:32:25 -07001873 resParmBuffer += sizeof(UINT32);
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001874 bufferSize -= sizeof(UINT32);
1875 }
Vadim Bendebury56797522015-05-20 10:32:25 -07001876 // Session nonce should be updated before parameter encryption
1877 if(tag == TPM_ST_SESSIONS)
1878 {
1879 UpdateTPMNonce(MAX_SESSION_NUM, responseNonces);
1880 // Encrypt first parameter if applicable. Parameter encryption should
1881 // happen after nonce update and before any rpHash is computed.
1882 // If the encrypt session is associated with a handle, the authValue of
1883 // this handle will be concatenated with sessionAuth to generate
1884 // encryption key, no matter if the handle is the session bound entity
1885 // or not. The authValue is added to sessionAuth only when the authValue
1886 // is available.
1887 if(s_encryptSessionIndex != UNDEFINED_INDEX)
1888 {
1889 UINT32 size;
1890 TPM2B_AUTH extraKey;
1891 // Get size of the leading size field
1892 if( s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED
1893 && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex],
1894 commandCode, s_encryptSessionIndex)
1895 )
1896 {
1897 extraKey.b.size =
1898 EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex],
1899 &extraKey.t.buffer);
1900 }
1901 else
1902 {
1903 extraKey.b.size = 0;
1904 }
1905 size = EncryptSize(commandCode);
1906 CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex],
1907 &s_nonceCaller[s_encryptSessionIndex].b,
1908 (UINT16)size,
1909 &extraKey,
1910 resParmBuffer);
1911 }
1912 }
1913 // Audit session should be updated first regardless of the tag.
1914 // A command with no session may trigger a change of the exclusivity state.
1915 UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer);
1916 // Audit command.
1917 CommandAudit(commandCode, resParmSize, resParmBuffer);
1918 // Process command with sessions.
1919 if(tag == TPM_ST_SESSIONS)
1920 {
1921 UINT32 i;
1922 BYTE *buffer;
1923 TPM2B_DIGEST responseAuths[MAX_SESSION_NUM];
1924 pAssert(s_sessionNum > 0);
1925 // Iterate over each session in the command session area, and create
1926 // corresponding sessions for response.
1927 for(i = 0; i < s_sessionNum; i++)
1928 {
1929 BuildSingleResponseAuth(
1930 i,
1931 commandCode,
1932 resParmSize,
1933 resParmBuffer,
1934 &responseAuths[i]);
1935 // Make sure that continueSession is SET on any Password session.
1936 // This makes it marginally easier for the management software
1937 // to keep track of the closed sessions.
1938 if( s_attributes[i].continueSession == CLEAR
1939 && s_sessionHandles[i] == TPM_RS_PW)
1940 {
1941 s_attributes[i].continueSession = SET;
1942 }
1943 }
1944 // Assemble Response Sessions.
1945 *resSessionSize = 0;
1946 buffer = resParmBuffer + resParmSize;
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001947 bufferSize -= resParmSize;
Vadim Bendebury56797522015-05-20 10:32:25 -07001948 for(i = 0; i < s_sessionNum; i++)
1949 {
1950 *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i],
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001951 &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -07001952 *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i],
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001953 &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -07001954 *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i],
Jocelyn Bohr32be4042015-07-29 15:14:01 -07001955 &buffer, &bufferSize);
Vadim Bendebury56797522015-05-20 10:32:25 -07001956 }
1957 // Update internal sessions after completing response buffer computation.
1958 UpdateInternalSession();
1959 }
1960 else
1961 {
1962 // Process command with no session.
1963 *resSessionSize = 0;
1964 }
1965 return;
1966}