/src/tpm2/SessionProcess.c
Line | Count | Source (jump to first uncovered line) |
1 | | // 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 | | // |
29 | | BOOL |
30 | | IsDAExempted( |
31 | | TPM_HANDLE handle // IN: entity handle |
32 | | ) |
33 | 957 | { |
34 | 957 | BOOL result = FALSE; |
35 | 957 | switch(HandleGetType(handle)) |
36 | 957 | { |
37 | 844 | case TPM_HT_PERMANENT: |
38 | | // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from |
39 | | // DA protection. |
40 | 844 | result = (handle != TPM_RH_LOCKOUT); |
41 | 844 | 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 | 0 | case TPM_HT_TRANSIENT: |
45 | 0 | { |
46 | 0 | OBJECT *object; |
47 | 0 | object = ObjectGet(handle); |
48 | 0 | result = (object->publicArea.objectAttributes.noDA == SET); |
49 | 0 | break; |
50 | 0 | } |
51 | 0 | case TPM_HT_NV_INDEX: |
52 | 0 | { |
53 | 0 | NV_INDEX nvIndex; |
54 | 0 | NvGetIndexInfo(handle, &nvIndex); |
55 | 0 | result = (nvIndex.publicArea.attributes.TPMA_NV_NO_DA == SET); |
56 | 0 | break; |
57 | 0 | } |
58 | 113 | case TPM_HT_PCR: |
59 | | // PCRs are always exempted from DA. |
60 | 113 | result = TRUE; |
61 | 113 | break; |
62 | 0 | default: |
63 | 0 | break; |
64 | 957 | } |
65 | 957 | return result; |
66 | 957 | } |
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 | | // |
80 | | static TPM_RC |
81 | | IncrementLockout( |
82 | | UINT32 sessionIndex |
83 | | ) |
84 | 16 | { |
85 | 16 | TPM_HANDLE handle = s_associatedHandles[sessionIndex]; |
86 | 16 | TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex]; |
87 | 16 | TPM_RC result; |
88 | 16 | 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 | 16 | if(sessionHandle == TPM_RS_PW) |
92 | 16 | { |
93 | 16 | if(IsDAExempted(handle)) |
94 | 13 | return TPM_RC_BAD_AUTH; |
95 | 16 | } |
96 | 0 | else |
97 | 0 | { |
98 | 0 | 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 | 0 | if(session->attributes.isLockoutBound == SET) |
104 | 0 | handle = TPM_RH_LOCKOUT; |
105 | 0 | if( session->attributes.isDaBound == CLEAR |
106 | 0 | && IsDAExempted(handle) |
107 | 0 | ) |
108 | | // If the handle was changed to TPM_RH_LOCKOUT, this will not return |
109 | | // TPM_RC_BAD_AUTH |
110 | 0 | return TPM_RC_BAD_AUTH; |
111 | 0 | } |
112 | 3 | if(handle == TPM_RH_LOCKOUT) |
113 | 3 | { |
114 | 3 | pAssert(gp.lockOutAuthEnabled); |
115 | 3 | 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 | 3 | if(gp.lockoutRecovery != 0) |
119 | 0 | { |
120 | 0 | result = NvIsAvailable(); |
121 | 0 | if(result != TPM_RC_SUCCESS) |
122 | 0 | { |
123 | | // No NV access for now. Put the TPM in pending mode. |
124 | 0 | s_DAPendingOnNV = TRUE; |
125 | 0 | } |
126 | 0 | else |
127 | 0 | { |
128 | | // Update NV. |
129 | 0 | NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); |
130 | 0 | g_updateNV = TRUE; |
131 | 0 | } |
132 | 0 | } |
133 | 3 | } |
134 | 0 | else |
135 | 0 | { |
136 | 0 | if(gp.recoveryTime != 0) |
137 | 0 | { |
138 | 0 | gp.failedTries++; |
139 | 0 | result = NvIsAvailable(); |
140 | 0 | if(result != TPM_RC_SUCCESS) |
141 | 0 | { |
142 | | // No NV access for now. Put the TPM in pending mode. |
143 | 0 | s_DAPendingOnNV = TRUE; |
144 | 0 | } |
145 | 0 | else |
146 | 0 | { |
147 | | // Record changes to NV. |
148 | 0 | NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries); |
149 | 0 | g_updateNV = TRUE; |
150 | 0 | } |
151 | 0 | } |
152 | 0 | } |
153 | | // Register a DA failure and reset the timers. |
154 | 3 | DARegisterFailure(handle); |
155 | 3 | return TPM_RC_AUTH_FAIL; |
156 | 16 | } |
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 | | // |
171 | | static BOOL |
172 | | IsSessionBindEntity( |
173 | | TPM_HANDLE associatedHandle, // IN: handle to be authorized |
174 | | SESSION *session // IN: associated session |
175 | | ) |
176 | 0 | { |
177 | 0 | TPM2B_NAME entity; // The bind value for the entity |
178 | | // If the session is not bound, return FALSE. |
179 | 0 | if(!session->attributes.isBound) |
180 | 0 | return FALSE; |
181 | | // Compute the bind value for the entity. |
182 | 0 | SessionComputeBoundEntity(associatedHandle, &entity); |
183 | | // Compare to the bind value in the session. |
184 | 0 | session->attributes.requestWasBound = |
185 | 0 | Memory2BEqual(&entity.b, &session->u1.boundEntity.b); |
186 | 0 | return session->attributes.requestWasBound; |
187 | 0 | } |
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 | | // |
208 | | static BOOL |
209 | | IsPolicySessionRequired( |
210 | | TPM_CC commandCode, // IN: command code |
211 | | UINT32 sessionIndex // IN: session index |
212 | | ) |
213 | 927 | { |
214 | 927 | AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex); |
215 | 927 | TPM_HT type = HandleGetType(s_associatedHandles[sessionIndex]); |
216 | 927 | if(role == AUTH_DUP) |
217 | 0 | return TRUE; |
218 | 927 | if(role == AUTH_ADMIN) |
219 | 0 | { |
220 | 0 | if(type == TPM_HT_TRANSIENT) |
221 | 0 | { |
222 | 0 | OBJECT *object = ObjectGet(s_associatedHandles[sessionIndex]); |
223 | 0 | if(object->publicArea.objectAttributes.adminWithPolicy == CLEAR) |
224 | 0 | return FALSE; |
225 | 0 | } |
226 | 0 | return TRUE; |
227 | 0 | } |
228 | | // |
229 | 927 | if(type == TPM_HT_PCR) |
230 | 105 | { |
231 | 105 | if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex])) |
232 | 0 | { |
233 | 0 | TPM2B_DIGEST policy; |
234 | 0 | TPMI_ALG_HASH policyAlg; |
235 | 0 | policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], |
236 | 0 | &policy); |
237 | 0 | if(policyAlg != TPM_ALG_NULL) |
238 | 0 | return TRUE; |
239 | 0 | } |
240 | 105 | } |
241 | 927 | return FALSE; |
242 | 927 | } |
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 | | // |
258 | | static BOOL |
259 | | IsAuthValueAvailable( |
260 | | TPM_HANDLE handle, // IN: handle of entity |
261 | | TPM_CC commandCode, // IN: commandCode |
262 | | UINT32 sessionIndex // IN: session index |
263 | | ) |
264 | 927 | { |
265 | 927 | BOOL result = FALSE; |
266 | 927 | switch(HandleGetType(handle)) |
267 | 927 | { |
268 | 822 | case TPM_HT_PERMANENT: |
269 | 822 | switch(handle) |
270 | 822 | { |
271 | | // At this point hierarchy availability has already been |
272 | | // checked so primary seed handles are always available here |
273 | 230 | case TPM_RH_OWNER: |
274 | 329 | case TPM_RH_ENDORSEMENT: |
275 | 601 | 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 | 797 | 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 | 822 | case TPM_RH_LOCKOUT: |
287 | 822 | result = TRUE; |
288 | 822 | break; |
289 | 0 | default: |
290 | | // Otherwise authValue is not available. |
291 | 0 | break; |
292 | 822 | } |
293 | 822 | break; |
294 | 822 | case TPM_HT_TRANSIENT: |
295 | | // A persistent object has already been loaded and the internal |
296 | | // handle changed. |
297 | 0 | { |
298 | 0 | OBJECT *object; |
299 | 0 | object = ObjectGet(handle); |
300 | | // authValue is always available for a sequence object. |
301 | 0 | if(ObjectIsSequence(object)) |
302 | 0 | { |
303 | 0 | result = TRUE; |
304 | 0 | break; |
305 | 0 | } |
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 | 0 | if( object->attributes.publicOnly == CLEAR |
311 | 0 | && (object->publicArea.objectAttributes.userWithAuth == SET |
312 | 0 | || (CommandAuthRole(commandCode, sessionIndex) == AUTH_ADMIN |
313 | 0 | && object->publicArea.objectAttributes.adminWithPolicy |
314 | 0 | == CLEAR))) |
315 | 0 | result = TRUE; |
316 | 0 | } |
317 | 0 | break; |
318 | 0 | case TPM_HT_NV_INDEX: |
319 | | // NV Index. |
320 | 0 | { |
321 | 0 | NV_INDEX nvIndex; |
322 | 0 | NvGetIndexInfo(handle, &nvIndex); |
323 | 0 | if(IsWriteOperation(commandCode)) |
324 | 0 | { |
325 | 0 | if (nvIndex.publicArea.attributes.TPMA_NV_AUTHWRITE == SET) |
326 | 0 | result = TRUE; |
327 | 0 | } |
328 | 0 | else |
329 | 0 | { |
330 | 0 | if (nvIndex.publicArea.attributes.TPMA_NV_AUTHREAD == SET) |
331 | 0 | result = TRUE; |
332 | 0 | } |
333 | 0 | } |
334 | 0 | break; |
335 | 105 | case TPM_HT_PCR: |
336 | | // PCR handle. |
337 | | // authValue is always allowed for PCR |
338 | 105 | result = TRUE; |
339 | 105 | break; |
340 | 0 | default: |
341 | | // Otherwise, authValue is not available |
342 | 0 | break; |
343 | 927 | } |
344 | 927 | return result; |
345 | 927 | } |
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 | | // |
360 | | static BOOL |
361 | | IsAuthPolicyAvailable( |
362 | | TPM_HANDLE handle, // IN: handle of entity |
363 | | TPM_CC commandCode, // IN: commandCode |
364 | | UINT32 sessionIndex // IN: session index |
365 | | ) |
366 | 0 | { |
367 | 0 | BOOL result = FALSE; |
368 | 0 | switch(HandleGetType(handle)) |
369 | 0 | { |
370 | 0 | case TPM_HT_PERMANENT: |
371 | 0 | switch(handle) |
372 | 0 | { |
373 | | // At this point hierarchy availability has already been checked. |
374 | 0 | case TPM_RH_OWNER: |
375 | 0 | if (gp.ownerPolicy.t.size != 0) |
376 | 0 | result = TRUE; |
377 | 0 | break; |
378 | 0 | case TPM_RH_ENDORSEMENT: |
379 | 0 | if (gp.endorsementPolicy.t.size != 0) |
380 | 0 | result = TRUE; |
381 | 0 | break; |
382 | 0 | case TPM_RH_PLATFORM: |
383 | 0 | if (gc.platformPolicy.t.size != 0) |
384 | 0 | result = TRUE; |
385 | 0 | break; |
386 | 0 | case TPM_RH_LOCKOUT: |
387 | 0 | if(gp.lockoutPolicy.t.size != 0) |
388 | 0 | result = TRUE; |
389 | 0 | break; |
390 | 0 | default: |
391 | 0 | break; |
392 | 0 | } |
393 | 0 | break; |
394 | 0 | case TPM_HT_TRANSIENT: |
395 | 0 | { |
396 | | // Object handle. |
397 | | // An evict object would already have been loaded and given a |
398 | | // transient object handle by this point. |
399 | 0 | OBJECT *object = ObjectGet(handle); |
400 | | // Policy authorization is not available for an object with only |
401 | | // public portion loaded. |
402 | 0 | if(object->attributes.publicOnly == CLEAR) |
403 | 0 | { |
404 | | // Policy authorization is always available for an object but |
405 | | // is never available for a sequence. |
406 | 0 | if(!ObjectIsSequence(object)) |
407 | 0 | result = TRUE; |
408 | 0 | } |
409 | 0 | break; |
410 | 0 | } |
411 | 0 | case TPM_HT_NV_INDEX: |
412 | | // An NV Index. |
413 | 0 | { |
414 | 0 | NV_INDEX nvIndex; |
415 | 0 | NvGetIndexInfo(handle, &nvIndex); |
416 | | // If the policy size is not zero, check if policy can be used. |
417 | 0 | if(nvIndex.publicArea.authPolicy.t.size != 0) |
418 | 0 | { |
419 | | // If policy session is required for this handle, always |
420 | | // uses policy regardless of the attributes bit setting |
421 | 0 | if(IsPolicySessionRequired(commandCode, sessionIndex)) |
422 | 0 | result = TRUE; |
423 | | // Otherwise, the presence of the policy depends on the NV |
424 | | // attributes. |
425 | 0 | else if(IsWriteOperation(commandCode)) |
426 | 0 | { |
427 | 0 | if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYWRITE |
428 | 0 | == SET) |
429 | 0 | result = TRUE; |
430 | 0 | } |
431 | 0 | else |
432 | 0 | { |
433 | 0 | if ( nvIndex.publicArea.attributes.TPMA_NV_POLICYREAD |
434 | 0 | == SET) |
435 | 0 | result = TRUE; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | } |
439 | 0 | break; |
440 | 0 | case TPM_HT_PCR: |
441 | | // PCR handle. |
442 | 0 | if(PCRPolicyIsAvailable(handle)) |
443 | 0 | result = TRUE; |
444 | 0 | break; |
445 | 0 | default: |
446 | 0 | break; |
447 | 0 | } |
448 | 0 | return result; |
449 | 0 | } |
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 | | // |
458 | | static void |
459 | | ComputeCpHash( |
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 | 0 | { |
470 | 0 | UINT32 i; |
471 | 0 | HASH_STATE hashState; |
472 | 0 | 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 | 0 | cpHash->t.size = CryptStartHash(hashAlg, &hashState); |
482 | | // Add commandCode. |
483 | 0 | CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode); |
484 | | // Add authNames for each of the handles. |
485 | 0 | for(i = 0; i < handleNum; i++) |
486 | 0 | { |
487 | 0 | name.t.size = EntityGetName(handles[i], &name.t.name); |
488 | 0 | CryptUpdateDigest2B(&hashState, &name.b); |
489 | 0 | } |
490 | | // Add the parameters. |
491 | 0 | CryptUpdateDigest(&hashState, parmBufferSize, parmBuffer); |
492 | | // Complete the hash. |
493 | 0 | CryptCompleteHash2B(&hashState, &cpHash->b); |
494 | | // If the nameHash is needed, compute it here. |
495 | 0 | if(nameHash != NULL) |
496 | 0 | { |
497 | | // Start name hash. hashState may be reused. |
498 | 0 | nameHash->t.size = CryptStartHash(hashAlg, &hashState); |
499 | | // Adding names. |
500 | 0 | for(i = 0; i < handleNum; i++) |
501 | 0 | { |
502 | 0 | name.t.size = EntityGetName(handles[i], &name.t.name); |
503 | 0 | CryptUpdateDigest2B(&hashState, &name.b); |
504 | 0 | } |
505 | | // Complete hash. |
506 | 0 | CryptCompleteHash2B(&hashState, &nameHash->b); |
507 | 0 | } |
508 | 0 | return; |
509 | 0 | } |
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 | | // |
523 | | static TPM_RC |
524 | | CheckPWAuthSession( |
525 | | UINT32 sessionIndex // IN: index of session to be processed |
526 | | ) |
527 | 927 | { |
528 | 927 | TPM2B_AUTH authValue; |
529 | 927 | TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex]; |
530 | | // Strip trailing zeros from the password. |
531 | 927 | MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]); |
532 | | // Get the auth value and size. |
533 | 927 | authValue.t.size = EntityGetAuthValue(associatedHandle, &authValue.t.buffer); |
534 | | // Success if the digests are identical. |
535 | 927 | if(Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &authValue.b)) |
536 | 911 | { |
537 | 911 | return TPM_RC_SUCCESS; |
538 | 911 | } |
539 | 16 | else // if the digests are not identical |
540 | 16 | { |
541 | | // Invoke DA protection if applicable. |
542 | 16 | return IncrementLockout(sessionIndex); |
543 | 16 | } |
544 | 927 | } |
545 | | // |
546 | | // |
547 | | // ComputeCommandHMAC() |
548 | | // |
549 | | // This function computes the HMAC for an authorization session in a command. |
550 | | // |
551 | | static void |
552 | | ComputeCommandHMAC( |
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 | 0 | { |
558 | 0 | TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2)); |
559 | 0 | TPM2B_KEY key; |
560 | 0 | BYTE marshalBuffer[sizeof(TPMA_SESSION)]; |
561 | 0 | BYTE *buffer; |
562 | 0 | INT32 bufferSize; |
563 | 0 | UINT32 marshalSize; |
564 | 0 | HMAC_STATE hmacState; |
565 | 0 | TPM2B_NONCE *nonceDecrypt; |
566 | 0 | TPM2B_NONCE *nonceEncrypt; |
567 | 0 | SESSION *session; |
568 | 0 | TPM_HT sessionHandleType = |
569 | 0 | HandleGetType(s_sessionHandles[sessionIndex]); |
570 | 0 | nonceDecrypt = NULL; |
571 | 0 | 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 | 0 | if( sessionIndex == 0 |
577 | 0 | && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) |
578 | 0 | { |
579 | | // If there is a decrypt session and if this is not the decrypt session, |
580 | | // then an extra nonce may be needed. |
581 | 0 | if( s_decryptSessionIndex != UNDEFINED_INDEX |
582 | 0 | && s_decryptSessionIndex != sessionIndex) |
583 | 0 | { |
584 | | // Will add the nonce for the decrypt session. |
585 | 0 | SESSION *decryptSession |
586 | 0 | = SessionGet(s_sessionHandles[s_decryptSessionIndex]); |
587 | 0 | nonceDecrypt = &decryptSession->nonceTPM; |
588 | 0 | } |
589 | | // Now repeat for the encrypt session. |
590 | 0 | if( s_encryptSessionIndex != UNDEFINED_INDEX |
591 | 0 | && s_encryptSessionIndex != sessionIndex |
592 | | // |
593 | 0 | && s_encryptSessionIndex != s_decryptSessionIndex) |
594 | 0 | { |
595 | | // Have to have the nonce for the encrypt session. |
596 | 0 | SESSION *encryptSession |
597 | 0 | = SessionGet(s_sessionHandles[s_encryptSessionIndex]); |
598 | 0 | nonceEncrypt = &encryptSession->nonceTPM; |
599 | 0 | } |
600 | 0 | } |
601 | | // Continue with the HMAC processing. |
602 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
603 | | // Generate HMAC key. |
604 | 0 | 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 | 0 | if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) |
614 | 0 | { |
615 | | // used for auth so see if this is a policy session with authValue needed |
616 | | // or an hmac session that is not bound |
617 | 0 | if (((sessionHandleType == TPM_HT_POLICY_SESSION) |
618 | 0 | && (session->attributes.isAuthValueNeeded == SET)) |
619 | 0 | || ((sessionHandleType == TPM_HT_HMAC_SESSION) |
620 | 0 | && !IsSessionBindEntity(s_associatedHandles[sessionIndex], session)) |
621 | 0 | ) |
622 | 0 | { |
623 | | // add the authValue to the HMAC key |
624 | 0 | pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer)); |
625 | 0 | key.t.size = key.t.size |
626 | 0 | + EntityGetAuthValue(s_associatedHandles[sessionIndex], |
627 | 0 | (AUTH_VALUE *)&(key.t.buffer[key.t.size])); |
628 | 0 | } |
629 | 0 | } |
630 | | // if the HMAC key size is 0, a NULL string HMAC is allowed |
631 | 0 | if( key.t.size == 0 |
632 | 0 | && s_inputAuthValues[sessionIndex].t.size == 0) |
633 | 0 | { |
634 | 0 | hmac->t.size = 0; |
635 | 0 | return; |
636 | 0 | } |
637 | | // Start HMAC |
638 | 0 | hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState); |
639 | | // Add cpHash |
640 | 0 | CryptUpdateDigest2B(&hmacState, &cpHash->b); |
641 | | // Add nonceCaller |
642 | 0 | CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b); |
643 | | // Add nonceTPM |
644 | 0 | CryptUpdateDigest2B(&hmacState, &session->nonceTPM.b); |
645 | | // If needed, add nonceTPM for decrypt session |
646 | 0 | if(nonceDecrypt != NULL) |
647 | 0 | CryptUpdateDigest2B(&hmacState, &nonceDecrypt->b); |
648 | | // If needed, add nonceTPM for encrypt session |
649 | 0 | if(nonceEncrypt != NULL) |
650 | 0 | CryptUpdateDigest2B(&hmacState, &nonceEncrypt->b); |
651 | | // Add sessionAttributes |
652 | 0 | buffer = marshalBuffer; |
653 | 0 | bufferSize = sizeof(TPMA_SESSION); |
654 | 0 | marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), |
655 | 0 | &buffer, &bufferSize); |
656 | 0 | CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer); |
657 | | // Complete the HMAC computation |
658 | 0 | CryptCompleteHMAC2B(&hmacState, &hmac->b); |
659 | 0 | return; |
660 | 0 | } |
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 | | // |
676 | | static TPM_RC |
677 | | CheckSessionHMAC( |
678 | | UINT32 sessionIndex, // IN: index of session to be processed |
679 | | TPM2B_DIGEST *cpHash // IN: cpHash of the command |
680 | | ) |
681 | 0 | { |
682 | 0 | TPM2B_DIGEST hmac; // authHMAC for comparing |
683 | | // Compute authHMAC |
684 | 0 | ComputeCommandHMAC(sessionIndex, cpHash, &hmac); |
685 | | // Compare the input HMAC with the authHMAC computed above. |
686 | 0 | if(!Memory2BEqual(&s_inputAuthValues[sessionIndex].b, &hmac.b)) |
687 | 0 | { |
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 | 0 | return IncrementLockout(sessionIndex); |
692 | 0 | } |
693 | 0 | return TPM_RC_SUCCESS; |
694 | 0 | } |
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 | | // |
721 | | static TPM_RC |
722 | | CheckPolicyAuthSession( |
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 | 0 | { |
730 | 0 | TPM_RC result = TPM_RC_SUCCESS; |
731 | 0 | SESSION *session; |
732 | 0 | TPM2B_DIGEST authPolicy; |
733 | 0 | TPMI_ALG_HASH policyAlg; |
734 | 0 | UINT8 locality; |
735 | | // Initialize pointer to the auth session. |
736 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
737 | | // If the command is TPM_RC_PolicySecret(), make sure that |
738 | | // either password or authValue is required |
739 | 0 | if( commandCode == TPM_CC_PolicySecret |
740 | 0 | && session->attributes.isPasswordNeeded == CLEAR |
741 | 0 | && session->attributes.isAuthValueNeeded == CLEAR) |
742 | 0 | return TPM_RC_MODE; |
743 | | // See if the PCR counter for the session is still valid. |
744 | 0 | if( !SessionPCRValueIsCurrent(s_sessionHandles[sessionIndex]) ) |
745 | 0 | return TPM_RC_PCR_CHANGED; |
746 | | // Get authPolicy. |
747 | 0 | policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], |
748 | 0 | &authPolicy); |
749 | | // Compare authPolicy. |
750 | 0 | if(!Memory2BEqual(&session->u2.policyDigest.b, &authPolicy.b)) |
751 | 0 | return TPM_RC_POLICY_FAIL; |
752 | | // Policy is OK so check if the other factors are correct |
753 | | // Compare policy hash algorithm. |
754 | 0 | if(policyAlg != session->authHashAlg) |
755 | 0 | return TPM_RC_POLICY_FAIL; |
756 | | // Compare timeout. |
757 | 0 | if(session->timeOut != 0) |
758 | 0 | { |
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 | 0 | result = NvIsAvailable(); |
762 | 0 | if(result != TPM_RC_SUCCESS) |
763 | 0 | return result; |
764 | 0 | if(session->timeOut < go.clock) |
765 | 0 | return TPM_RC_EXPIRED; |
766 | 0 | } |
767 | | // If command code is provided it must match |
768 | 0 | if(session->commandCode != 0) |
769 | 0 | { |
770 | 0 | if(session->commandCode != commandCode) |
771 | 0 | return TPM_RC_POLICY_CC; |
772 | 0 | } |
773 | 0 | else |
774 | 0 | { |
775 | | // If command requires a DUP or ADMIN authorization, the session must have |
776 | | // command code set. |
777 | 0 | AUTH_ROLE role = CommandAuthRole(commandCode, sessionIndex); |
778 | 0 | if(role == AUTH_ADMIN || role == AUTH_DUP) |
779 | 0 | return TPM_RC_POLICY_FAIL; |
780 | 0 | } |
781 | | // Check command locality. |
782 | 0 | { |
783 | 0 | BYTE sessionLocality[sizeof(TPMA_LOCALITY)]; |
784 | 0 | BYTE *buffer = sessionLocality; |
785 | 0 | INT32 bufferSize = sizeof(TPMA_LOCALITY); |
786 | | // Get existing locality setting in canonical form |
787 | 0 | TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, &bufferSize); |
788 | | // See if the locality has been set |
789 | 0 | if(sessionLocality[0] != 0) |
790 | 0 | { |
791 | | // If so, get the current locality |
792 | 0 | locality = _plat__LocalityGet(); |
793 | 0 | if (locality < 5) |
794 | 0 | { |
795 | 0 | if( ((sessionLocality[0] & (1 << locality)) == 0) |
796 | 0 | || sessionLocality[0] > 31) |
797 | 0 | return TPM_RC_LOCALITY; |
798 | 0 | } |
799 | 0 | else if (locality > 31) |
800 | 0 | { |
801 | 0 | if(sessionLocality[0] != locality) |
802 | 0 | return TPM_RC_LOCALITY; |
803 | 0 | } |
804 | 0 | else |
805 | 0 | { |
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 | 0 | return TPM_RC_LOCALITY; |
810 | 0 | } |
811 | 0 | } |
812 | 0 | } // end of locality check |
813 | | // Check physical presence. |
814 | 0 | if( session->attributes.isPPRequired == SET |
815 | 0 | && !_plat__PhysicalPresenceAsserted()) |
816 | 0 | 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 | 0 | if(session->u1.cpHash.b.size != 0) |
820 | 0 | { |
821 | 0 | if(session->attributes.iscpHashDefined) |
822 | 0 | { |
823 | | // Compare cpHash. |
824 | 0 | if(!Memory2BEqual(&session->u1.cpHash.b, &cpHash->b)) |
825 | 0 | return TPM_RC_POLICY_FAIL; |
826 | 0 | } |
827 | 0 | else |
828 | 0 | { |
829 | | // Compare nameHash. |
830 | | // When cpHash is not defined, nameHash is placed in its space. |
831 | 0 | if(!Memory2BEqual(&session->u1.cpHash.b, &nameHash->b)) |
832 | 0 | return TPM_RC_POLICY_FAIL; |
833 | 0 | } |
834 | 0 | } |
835 | 0 | if(session->attributes.checkNvWritten) |
836 | 0 | { |
837 | 0 | NV_INDEX nvIndex; |
838 | | // If this is not an NV index, the policy makes no sense so fail it. |
839 | 0 | if(HandleGetType(s_associatedHandles[sessionIndex])!= TPM_HT_NV_INDEX) |
840 | 0 | return TPM_RC_POLICY_FAIL; |
841 | | // Get the index data |
842 | 0 | NvGetIndexInfo(s_associatedHandles[sessionIndex], &nvIndex); |
843 | | // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state |
844 | 0 | if( (nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) |
845 | 0 | != (session->attributes.nvWrittenState == SET)) |
846 | 0 | return TPM_RC_POLICY_FAIL; |
847 | 0 | } |
848 | 0 | return TPM_RC_SUCCESS; |
849 | 0 | } |
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 | | // |
863 | | static TPM_RC |
864 | | RetrieveSessionData ( |
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 | 1.11k | { |
871 | 1.11k | int sessionIndex; |
872 | 1.11k | int i; |
873 | 1.11k | TPM_RC result; |
874 | 1.11k | SESSION *session; |
875 | 1.11k | TPM_HT sessionType; |
876 | 1.11k | s_decryptSessionIndex = UNDEFINED_INDEX; |
877 | 1.11k | s_encryptSessionIndex = UNDEFINED_INDEX; |
878 | 1.11k | s_auditSessionIndex = UNDEFINED_INDEX; |
879 | 2.08k | for(sessionIndex = 0; bufferSize > 0; sessionIndex++) |
880 | 1.14k | { |
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 | 1.14k | if(sessionIndex == MAX_SESSION_NUM) |
885 | 2 | 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 | 1.14k | s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; |
889 | | // First parameter: Session handle. |
890 | 1.14k | result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex], |
891 | 1.14k | &sessionBuffer, &bufferSize, TRUE); |
892 | 1.14k | if(result != TPM_RC_SUCCESS) |
893 | 114 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
894 | | // Second parameter: Nonce. |
895 | 1.03k | result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex], |
896 | 1.03k | &sessionBuffer, &bufferSize); |
897 | 1.03k | if(result != TPM_RC_SUCCESS) |
898 | 10 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
899 | | // Third parameter: sessionAttributes. |
900 | 1.02k | result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex], |
901 | 1.02k | &sessionBuffer, &bufferSize); |
902 | 1.02k | if(result != TPM_RC_SUCCESS) |
903 | 6 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
904 | | // Fourth parameter: authValue (PW or HMAC). |
905 | 1.01k | result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex], |
906 | 1.01k | &sessionBuffer, &bufferSize); |
907 | 1.01k | if(result != TPM_RC_SUCCESS) |
908 | 33 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
909 | 982 | if(s_sessionHandles[sessionIndex] == TPM_RS_PW) |
910 | 976 | { |
911 | | // A PWAP session needs additional processing. |
912 | | // Can't have any attributes set other than continueSession bit |
913 | 976 | if( s_attributes[sessionIndex].encrypt |
914 | 976 | || s_attributes[sessionIndex].decrypt |
915 | 976 | || s_attributes[sessionIndex].audit |
916 | 976 | || s_attributes[sessionIndex].auditExclusive |
917 | 976 | || s_attributes[sessionIndex].auditReset |
918 | 976 | ) |
919 | 7 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; |
920 | | // The nonce size must be zero. |
921 | 969 | if(s_nonceCaller[sessionIndex].t.size != 0) |
922 | 2 | return TPM_RC_NONCE + TPM_RC_S + g_rcIndex[sessionIndex]; |
923 | 967 | continue; |
924 | 969 | } |
925 | | // For not password sessions... |
926 | | // Find out if the session is loaded. |
927 | 6 | if(!SessionIsLoaded(s_sessionHandles[sessionIndex])) |
928 | 6 | return TPM_RC_REFERENCE_S0 + sessionIndex; |
929 | 0 | sessionType = HandleGetType(s_sessionHandles[sessionIndex]); |
930 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
931 | | // Check if the session is an HMAC/policy session. |
932 | 0 | if( ( session->attributes.isPolicy == SET |
933 | 0 | && sessionType == TPM_HT_HMAC_SESSION |
934 | 0 | ) |
935 | 0 | || ( session->attributes.isPolicy == CLEAR |
936 | 0 | && sessionType == TPM_HT_POLICY_SESSION |
937 | 0 | ) |
938 | 0 | ) |
939 | 0 | return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex]; |
940 | | // Check that this handle has not previously been used. |
941 | 0 | for(i = 0; i < sessionIndex; i++) |
942 | 0 | { |
943 | 0 | if(s_sessionHandles[i] == s_sessionHandles[sessionIndex]) |
944 | 0 | return TPM_RC_HANDLE + TPM_RC_S + g_rcIndex[sessionIndex]; |
945 | 0 | } |
946 | | // If the session is used for parameter encryption or audit as well, set |
947 | | // the corresponding indices. |
948 | | // First process decrypt. |
949 | 0 | if(s_attributes[sessionIndex].decrypt) |
950 | 0 | { |
951 | | // Check if the commandCode allows command parameter encryption. |
952 | 0 | if(DecryptSize(commandCode) == 0) |
953 | 0 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; |
954 | | // Encrypt attribute can only appear in one session |
955 | 0 | if(s_decryptSessionIndex != UNDEFINED_INDEX) |
956 | 0 | 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 | 0 | if(session->symmetric.algorithm == TPM_ALG_NULL) |
959 | 0 | 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 | 0 | s_decryptSessionIndex = sessionIndex; |
963 | 0 | } |
964 | | // Now process encrypt. |
965 | 0 | if(s_attributes[sessionIndex].encrypt) |
966 | 0 | { |
967 | | // Check if the commandCode allows response parameter encryption. |
968 | 0 | if(EncryptSize(commandCode) == 0) |
969 | 0 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; |
970 | | // Encrypt attribute can only appear in one session. |
971 | 0 | if(s_encryptSessionIndex != UNDEFINED_INDEX) |
972 | 0 | 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 | 0 | if(session->symmetric.algorithm == TPM_ALG_NULL) |
975 | 0 | 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 | 0 | s_encryptSessionIndex = sessionIndex; |
979 | 0 | } |
980 | | // At last process audit. |
981 | 0 | if(s_attributes[sessionIndex].audit) |
982 | 0 | { |
983 | | // Audit attribute can only appear in one session. |
984 | 0 | if(s_auditSessionIndex != UNDEFINED_INDEX) |
985 | 0 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; |
986 | | // An audit session can not be policy session. |
987 | 0 | if( HandleGetType(s_sessionHandles[sessionIndex]) |
988 | 0 | == TPM_HT_POLICY_SESSION) |
989 | 0 | 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 | 0 | if( s_attributes[sessionIndex].auditReset == CLEAR |
994 | 0 | && session->attributes.isAudit == SET) |
995 | 0 | { |
996 | | // Not first use or reset. If auditExlusive is SET, then this |
997 | | // session must be the current exclusive session. |
998 | 0 | if( s_attributes[sessionIndex].auditExclusive == SET |
999 | 0 | && g_exclusiveAuditSession != s_sessionHandles[sessionIndex]) |
1000 | 0 | return TPM_RC_EXCLUSIVE; |
1001 | 0 | } |
1002 | 0 | s_auditSessionIndex = sessionIndex; |
1003 | 0 | } |
1004 | | // Initialize associated handle as undefined. This will be changed when |
1005 | | // the handles are processed. |
1006 | 0 | s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; |
1007 | 0 | } |
1008 | | // Set the number of sessions found. |
1009 | 935 | *sessionCount = sessionIndex; |
1010 | 935 | return TPM_RC_SUCCESS; |
1011 | 1.11k | } |
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 | | // |
1027 | | static TPM_RC |
1028 | | CheckLockedOut( |
1029 | | BOOL lockoutAuthCheck // IN: TRUE if checking is for lockoutAuth |
1030 | | ) |
1031 | 25 | { |
1032 | 25 | 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 | 25 | result = NvIsAvailable(); |
1037 | 25 | if(result != TPM_RC_SUCCESS && gp.orderlyState != SHUTDOWN_NONE) |
1038 | 0 | return result; |
1039 | | // Check if DA info needs to be updated in NV. |
1040 | 25 | if(s_DAPendingOnNV) |
1041 | 0 | { |
1042 | | // If NV is accessible, ... |
1043 | 0 | if(result == TPM_RC_SUCCESS) |
1044 | 0 | { |
1045 | | // ... write the pending DA data and proceed. |
1046 | 0 | NvWriteReserved(NV_LOCKOUT_AUTH_ENABLED, |
1047 | 0 | &gp.lockOutAuthEnabled); |
1048 | 0 | NvWriteReserved(NV_FAILED_TRIES, &gp.failedTries); |
1049 | 0 | g_updateNV = TRUE; |
1050 | 0 | s_DAPendingOnNV = FALSE; |
1051 | 0 | } |
1052 | 0 | else |
1053 | 0 | { |
1054 | | // Otherwise no authorization can be checked. |
1055 | 0 | return result; |
1056 | 0 | } |
1057 | 0 | } |
1058 | | // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth |
1059 | | // is disabled... |
1060 | 25 | if(lockoutAuthCheck) |
1061 | 25 | { |
1062 | 25 | if(gp.lockOutAuthEnabled == FALSE) |
1063 | 0 | return TPM_RC_LOCKOUT; |
1064 | 25 | } |
1065 | 0 | else |
1066 | 0 | { |
1067 | | // ... or if the number of failed tries has been maxed out. |
1068 | 0 | if(gp.failedTries >= gp.maxTries) |
1069 | 0 | return TPM_RC_LOCKOUT; |
1070 | 0 | } |
1071 | 25 | return TPM_RC_SUCCESS; |
1072 | 25 | } |
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 | | // |
1094 | | static TPM_RC |
1095 | | CheckAuthSession( |
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 | 927 | { |
1103 | 927 | TPM_RC result; |
1104 | 927 | SESSION *session = NULL; |
1105 | 927 | TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex]; |
1106 | 927 | TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex]; |
1107 | 927 | TPM_HT sessionHandleType = HandleGetType(sessionHandle); |
1108 | 927 | pAssert(sessionHandle != TPM_RH_UNASSIGNED); |
1109 | 927 | if(sessionHandle != TPM_RS_PW) |
1110 | 0 | session = SessionGet(sessionHandle); |
1111 | 927 | 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 | 927 | if( sessionHandleType != TPM_HT_POLICY_SESSION |
1115 | 927 | || session->attributes.isAuthValueNeeded |
1116 | 927 | || session->attributes.isPasswordNeeded) |
1117 | 927 | { |
1118 | | // See if entity is subject to lockout. |
1119 | 927 | if(!IsDAExempted(associatedHandle)) |
1120 | 25 | { |
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 | 25 | result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT); |
1125 | 25 | if(result != TPM_RC_SUCCESS) |
1126 | 0 | return result; |
1127 | 25 | } |
1128 | 927 | } |
1129 | 927 | if(associatedHandle == TPM_RH_PLATFORM) |
1130 | 272 | { |
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 | 272 | if( PhysicalPresenceIsRequired(commandCode) |
1134 | 272 | && !_plat__PhysicalPresenceAsserted() |
1135 | 272 | ) |
1136 | 0 | return TPM_RC_PP; |
1137 | 272 | } |
1138 | | // If a policy session is required, make sure that it is being used. |
1139 | 927 | if( IsPolicySessionRequired(commandCode, sessionIndex) |
1140 | 927 | && sessionHandleType != TPM_HT_POLICY_SESSION) |
1141 | 0 | return TPM_RC_AUTH_TYPE; |
1142 | | // If this is a PW authorization, check it and return. |
1143 | 927 | if(sessionHandle == TPM_RS_PW) |
1144 | 927 | { |
1145 | 927 | if(IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex)) |
1146 | 927 | return CheckPWAuthSession(sessionIndex); |
1147 | 0 | else |
1148 | 0 | return TPM_RC_AUTH_UNAVAILABLE; |
1149 | 927 | } |
1150 | | // If this is a policy session, ... |
1151 | 0 | if(sessionHandleType == TPM_HT_POLICY_SESSION) |
1152 | 0 | { |
1153 | | // ... see if the entity has a policy, ... |
1154 | 0 | if( !IsAuthPolicyAvailable(associatedHandle, commandCode, sessionIndex)) |
1155 | 0 | return TPM_RC_AUTH_UNAVAILABLE; |
1156 | | // ... and check the policy session. |
1157 | 0 | result = CheckPolicyAuthSession(sessionIndex, commandCode, |
1158 | 0 | cpHash, nameHash); |
1159 | 0 | if (result != TPM_RC_SUCCESS) |
1160 | 0 | return result; |
1161 | 0 | } |
1162 | 0 | else |
1163 | 0 | { |
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 | 0 | if(!IsAuthValueAvailable(associatedHandle, commandCode, sessionIndex)) |
1168 | 0 | return TPM_RC_AUTH_UNAVAILABLE; |
1169 | 0 | } |
1170 | | // At this point, the session must be either a policy or an HMAC session. |
1171 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
1172 | 0 | if( sessionHandleType == TPM_HT_POLICY_SESSION |
1173 | 0 | && session->attributes.isPasswordNeeded == SET) |
1174 | 0 | { |
1175 | | // For policy session that requires a password, check it as PWAP session. |
1176 | 0 | return CheckPWAuthSession(sessionIndex); |
1177 | 0 | } |
1178 | 0 | else |
1179 | 0 | { |
1180 | | // For other policy or HMAC sessions, have its HMAC checked. |
1181 | 0 | return CheckSessionHMAC(sessionIndex, cpHash); |
1182 | 0 | } |
1183 | 0 | } |
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 | | // |
1197 | | static TPM_RC |
1198 | | CheckCommandAudit( |
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 | 9.38k | { |
1206 | 9.38k | 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 | 9.38k | if(CommandAuditIsRequired(commandCode)) |
1210 | 0 | { |
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 | 0 | if( gr.commandAuditDigest.t.size == 0 |
1216 | 0 | || commandCode == TPM_CC_GetCommandAuditDigest) |
1217 | 0 | { |
1218 | 0 | result = NvIsAvailable(); |
1219 | 0 | if(result != TPM_RC_SUCCESS) |
1220 | 0 | return result; |
1221 | 0 | } |
1222 | 0 | ComputeCpHash(gp.auditHashAlg, commandCode, handleNum, |
1223 | 0 | handles, parmBufferSize, parmBufferStart, |
1224 | 0 | &s_cpHashForCommandAudit, NULL); |
1225 | 0 | } |
1226 | 9.38k | return TPM_RC_SUCCESS; |
1227 | 9.38k | } |
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 | | // |
1241 | | TPM_RC |
1242 | | ParseSessionBuffer( |
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 | 1.11k | { |
1252 | 1.11k | TPM_RC result; |
1253 | 1.11k | UINT32 i; |
1254 | 1.11k | INT32 size = 0; |
1255 | 1.11k | TPM2B_AUTH extraKey; |
1256 | 1.11k | UINT32 sessionIndex; |
1257 | 1.11k | SESSION *session; |
1258 | 1.11k | TPM2B_DIGEST cpHash; |
1259 | 1.11k | TPM2B_DIGEST nameHash; |
1260 | 1.11k | 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 | 1.11k | if(!IsSessionAllowed(commandCode)) |
1264 | 2 | return TPM_RC_AUTH_CONTEXT; |
1265 | | // Default-initialization. |
1266 | 1.11k | s_sessionNum = 0; |
1267 | 1.11k | cpHash.t.size = 0; |
1268 | 1.11k | result = RetrieveSessionData(commandCode, &s_sessionNum, |
1269 | 1.11k | sessionBufferStart, sessionBufferSize); |
1270 | 1.11k | if(result != TPM_RC_SUCCESS) |
1271 | 180 | return result; |
1272 | | // There is no command in the TPM spec that has more handles than |
1273 | | // MAX_SESSION_NUM. |
1274 | 935 | pAssert(handleNum <= MAX_SESSION_NUM); |
1275 | | // Associate the session with an authorization handle. |
1276 | 1.86k | for(i = 0; i < handleNum; i++) |
1277 | 929 | { |
1278 | 929 | if(CommandAuthRole(commandCode, i) != AUTH_NONE) |
1279 | 927 | { |
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 | 927 | if(i > (s_sessionNum - 1)) |
1285 | 0 | return TPM_RC_AUTH_MISSING; |
1286 | | // Record the handle associated with the authorization session |
1287 | 927 | s_associatedHandles[i] = handles[i]; |
1288 | 927 | } |
1289 | 929 | } |
1290 | | // Consistency checks are done first to avoid auth failure when the command |
1291 | | // will not be executed anyway. |
1292 | 1.84k | for(sessionIndex = 0; sessionIndex < s_sessionNum; sessionIndex++) |
1293 | 937 | { |
1294 | | // PW session must be an authorization session |
1295 | 937 | if(s_sessionHandles[sessionIndex] == TPM_RS_PW ) |
1296 | 937 | { |
1297 | 937 | if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED) |
1298 | 10 | return TPM_RC_HANDLE + g_rcIndex[sessionIndex]; |
1299 | 937 | } |
1300 | 0 | else |
1301 | 0 | { |
1302 | 0 | 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 | 0 | if(session->attributes.isTrialPolicy == SET) |
1306 | 0 | 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 | 0 | if(session->attributes.isDaBound == SET) |
1312 | 0 | { |
1313 | 0 | result = CheckLockedOut(session->attributes.isLockoutBound == SET); |
1314 | 0 | if(result != TPM_RC_SUCCESS) |
1315 | 0 | return result; |
1316 | 0 | } |
1317 | | // If the current cpHash is the right one, don't re-compute. |
1318 | 0 | if(cpHashAlg != session->authHashAlg) // different so compute |
1319 | 0 | { |
1320 | 0 | cpHashAlg = session->authHashAlg; // save this new algID |
1321 | 0 | ComputeCpHash(session->authHashAlg, commandCode, handleNum, |
1322 | 0 | handles, parmBufferSize, parmBufferStart, |
1323 | 0 | &cpHash, &nameHash); |
1324 | 0 | } |
1325 | | // If this session is for auditing, save the cpHash. |
1326 | 0 | if(s_attributes[sessionIndex].audit) |
1327 | 0 | s_cpHashForAudit = cpHash; |
1328 | 0 | } |
1329 | | // if the session has an associated handle, check the auth |
1330 | 927 | if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) |
1331 | 927 | { |
1332 | 927 | result = CheckAuthSession(commandCode, sessionIndex, |
1333 | 927 | &cpHash, &nameHash); |
1334 | 927 | if(result != TPM_RC_SUCCESS) |
1335 | 16 | return RcSafeAddToResult(result, |
1336 | 927 | TPM_RC_S + g_rcIndex[sessionIndex]); |
1337 | 927 | } |
1338 | 0 | else |
1339 | 0 | { |
1340 | | // a session that is not for authorization must either be encrypt, |
1341 | | // decrypt, or audit |
1342 | 0 | if( s_attributes[sessionIndex].audit == CLEAR |
1343 | 0 | && s_attributes[sessionIndex].encrypt == CLEAR |
1344 | 0 | && s_attributes[sessionIndex].decrypt == CLEAR) |
1345 | 0 | return TPM_RC_ATTRIBUTES + TPM_RC_S + g_rcIndex[sessionIndex]; |
1346 | | // check HMAC for encrypt/decrypt/audit only sessions |
1347 | 0 | result = CheckSessionHMAC(sessionIndex, &cpHash); |
1348 | 0 | if(result != TPM_RC_SUCCESS) |
1349 | 0 | return RcSafeAddToResult(result, |
1350 | 0 | TPM_RC_S + g_rcIndex[sessionIndex]); |
1351 | 0 | } |
1352 | 927 | } |
1353 | 909 | #ifdef TPM_CC_GetCommandAuditDigest |
1354 | | // Check if the command should be audited. |
1355 | 909 | result = CheckCommandAudit(commandCode, handleNum, handles, |
1356 | 909 | parmBufferStart, parmBufferSize); |
1357 | 909 | if(result != TPM_RC_SUCCESS) |
1358 | 0 | return result; // No session number to reference |
1359 | 909 | #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 | 909 | if(s_decryptSessionIndex != UNDEFINED_INDEX) |
1367 | 0 | { |
1368 | | // Get size of the leading size field in decrypt parameter |
1369 | 0 | if( s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED |
1370 | 0 | && IsAuthValueAvailable(s_associatedHandles[s_decryptSessionIndex], |
1371 | 0 | commandCode, |
1372 | 0 | s_decryptSessionIndex) |
1373 | 0 | ) |
1374 | 0 | { |
1375 | 0 | extraKey.b.size= |
1376 | 0 | EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], |
1377 | 0 | &extraKey.t.buffer); |
1378 | 0 | } |
1379 | 0 | else |
1380 | 0 | { |
1381 | 0 | extraKey.b.size = 0; |
1382 | 0 | } |
1383 | 0 | size = DecryptSize(commandCode); |
1384 | 0 | result = CryptParameterDecryption( |
1385 | 0 | s_sessionHandles[s_decryptSessionIndex], |
1386 | 0 | &s_nonceCaller[s_decryptSessionIndex].b, |
1387 | 0 | parmBufferSize, (UINT16)size, |
1388 | 0 | &extraKey, |
1389 | 0 | parmBufferStart); |
1390 | 0 | if(result != TPM_RC_SUCCESS) |
1391 | 0 | return RcSafeAddToResult(result, |
1392 | 0 | TPM_RC_S + g_rcIndex[s_decryptSessionIndex]); |
1393 | 0 | } |
1394 | 909 | return TPM_RC_SUCCESS; |
1395 | 909 | } |
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 | | // |
1409 | | TPM_RC |
1410 | | CheckAuthNoSession( |
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 | 8.48k | { |
1418 | 8.48k | UINT32 i; |
1419 | 8.48k | TPM_RC result = TPM_RC_SUCCESS; |
1420 | | // Check if the commandCode requires authorization |
1421 | 8.86k | for(i = 0; i < handleNum; i++) |
1422 | 388 | { |
1423 | 388 | if(CommandAuthRole(commandCode, i) != AUTH_NONE) |
1424 | 6 | return TPM_RC_AUTH_MISSING; |
1425 | 388 | } |
1426 | 8.47k | #ifdef TPM_CC_GetCommandAuditDigest |
1427 | | // Check if the command should be audited. |
1428 | 8.47k | result = CheckCommandAudit(commandCode, handleNum, handles, |
1429 | 8.47k | parmBufferStart, parmBufferSize); |
1430 | 8.47k | if(result != TPM_RC_SUCCESS) return result; |
1431 | 8.47k | #endif |
1432 | | // Initialize number of sessions to be 0 |
1433 | 8.47k | s_sessionNum = 0; |
1434 | 8.47k | return TPM_RC_SUCCESS; |
1435 | 8.47k | } |
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 | | // |
1449 | | static void |
1450 | | ComputeRpHash( |
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 | 0 | { |
1458 | | // The command result in rpHash is always TPM_RC_SUCCESS. |
1459 | 0 | TPM_RC responseCode = TPM_RC_SUCCESS; |
1460 | 0 | HASH_STATE hashState; |
1461 | | // rpHash := hash(responseCode || commandCode || parameters) |
1462 | | // Initiate hash creation. |
1463 | 0 | rpHash->t.size = CryptStartHash(hashAlg, &hashState); |
1464 | | // Add hash constituents. |
1465 | 0 | CryptUpdateDigestInt(&hashState, sizeof(TPM_RC), &responseCode); |
1466 | 0 | CryptUpdateDigestInt(&hashState, sizeof(TPM_CC), &commandCode); |
1467 | 0 | CryptUpdateDigest(&hashState, resParmBufferSize, resParmBuffer); |
1468 | | // Complete hash computation. |
1469 | 0 | CryptCompleteHash2B(&hashState, &rpHash->b); |
1470 | 0 | return; |
1471 | 0 | } |
1472 | | // |
1473 | | // |
1474 | | // InitAuditSession() |
1475 | | // |
1476 | | // This function initializes the audit data in an audit session. |
1477 | | // |
1478 | | static void |
1479 | | InitAuditSession( |
1480 | | SESSION *session // session to be initialized |
1481 | | ) |
1482 | 0 | { |
1483 | | // Mark session as an audit session. |
1484 | 0 | session->attributes.isAudit = SET; |
1485 | | // Audit session can not be bound. |
1486 | 0 | session->attributes.isBound = CLEAR; |
1487 | | // Size of the audit log is the size of session hash algorithm digest. |
1488 | 0 | session->u2.auditDigest.t.size = CryptGetHashDigestSize(session->authHashAlg); |
1489 | | // Set the original digest value to be 0. |
1490 | 0 | MemorySet(&session->u2.auditDigest.t.buffer, |
1491 | 0 | 0, |
1492 | 0 | session->u2.auditDigest.t.size); |
1493 | 0 | return; |
1494 | 0 | } |
1495 | | // |
1496 | | // |
1497 | | // Audit() |
1498 | | // |
1499 | | // This function updates the audit digest in an audit session. |
1500 | | // |
1501 | | static void |
1502 | | Audit( |
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 | 0 | { |
1509 | 0 | TPM2B_DIGEST rpHash; // rpHash for response |
1510 | 0 | HASH_STATE hashState; |
1511 | | // Compute rpHash |
1512 | 0 | ComputeRpHash(auditSession->authHashAlg, |
1513 | 0 | commandCode, |
1514 | 0 | resParmBufferSize, |
1515 | 0 | resParmBuffer, |
1516 | 0 | &rpHash); |
1517 | | // auditDigestnew := hash (auditDigestold || cpHash || rpHash) |
1518 | | // Start hash computation. |
1519 | 0 | CryptStartHash(auditSession->authHashAlg, &hashState); |
1520 | | // Add old digest. |
1521 | 0 | CryptUpdateDigest2B(&hashState, &auditSession->u2.auditDigest.b); |
1522 | | // Add cpHash and rpHash. |
1523 | 0 | CryptUpdateDigest2B(&hashState, &s_cpHashForAudit.b); |
1524 | 0 | CryptUpdateDigest2B(&hashState, &rpHash.b); |
1525 | | // Finalize the hash. |
1526 | 0 | CryptCompleteHash2B(&hashState, &auditSession->u2.auditDigest.b); |
1527 | 0 | return; |
1528 | 0 | } |
1529 | | #ifdef TPM_CC_GetCommandAuditDigest |
1530 | | // |
1531 | | // |
1532 | | // CommandAudit() |
1533 | | // |
1534 | | // This function updates the command audit digest. |
1535 | | // |
1536 | | static void |
1537 | | CommandAudit( |
1538 | | TPM_CC commandCode, // IN: commandCode |
1539 | | UINT32 resParmBufferSize, // IN: size of response parameter buffer |
1540 | | BYTE *resParmBuffer // IN: response parameter buffer |
1541 | | ) |
1542 | 6.77k | { |
1543 | 6.77k | if(CommandAuditIsRequired(commandCode)) |
1544 | 0 | { |
1545 | 0 | TPM2B_DIGEST rpHash; // rpHash for response |
1546 | 0 | HASH_STATE hashState; |
1547 | | // Compute rpHash. |
1548 | 0 | ComputeRpHash(gp.auditHashAlg, commandCode, resParmBufferSize, |
1549 | 0 | 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 | 0 | if(gr.commandAuditDigest.t.size == 1) |
1557 | 0 | { |
1558 | 0 | gr.commandAuditDigest.t.size = 0; |
1559 | 0 | return; |
1560 | 0 | } |
1561 | | // If the digest size is zero, need to start a new digest and increment |
1562 | | // the audit counter. |
1563 | 0 | if(gr.commandAuditDigest.t.size == 0) |
1564 | 0 | { |
1565 | 0 | gr.commandAuditDigest.t.size = CryptGetHashDigestSize(gp.auditHashAlg); |
1566 | 0 | MemorySet(gr.commandAuditDigest.t.buffer, |
1567 | 0 | 0, |
1568 | 0 | gr.commandAuditDigest.t.size); |
1569 | | // Bump the counter and save its value to NV. |
1570 | 0 | gp.auditCounter++; |
1571 | 0 | NvWriteReserved(NV_AUDIT_COUNTER, &gp.auditCounter); |
1572 | 0 | g_updateNV = TRUE; |
1573 | | // |
1574 | 0 | } |
1575 | | // auditDigestnew := hash (auditDigestold || cpHash || rpHash) |
1576 | | // Start hash computation. |
1577 | 0 | CryptStartHash(gp.auditHashAlg, &hashState); |
1578 | | // Add old digest. |
1579 | 0 | CryptUpdateDigest2B(&hashState, &gr.commandAuditDigest.b); |
1580 | | // Add cpHash |
1581 | 0 | CryptUpdateDigest2B(&hashState, &s_cpHashForCommandAudit.b); |
1582 | | // Add rpHash |
1583 | 0 | CryptUpdateDigest2B(&hashState, &rpHash.b); |
1584 | | // Finalize the hash. |
1585 | 0 | CryptCompleteHash2B(&hashState, &gr.commandAuditDigest.b); |
1586 | 0 | } |
1587 | 6.77k | return; |
1588 | 6.77k | } |
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 | | // |
1601 | | static void |
1602 | | UpdateAuditSessionStatus( |
1603 | | TPM_CC commandCode, // IN: commandCode |
1604 | | UINT32 resParmBufferSize, // IN: size of response parameter buffer |
1605 | | BYTE *resParmBuffer // IN: response parameter buffer |
1606 | | ) |
1607 | 6.77k | { |
1608 | 6.77k | UINT32 i; |
1609 | 6.77k | TPM_HANDLE auditSession = TPM_RH_UNASSIGNED; |
1610 | | // Iterate through sessions |
1611 | 7.00k | for (i = 0; i < s_sessionNum; i++) |
1612 | 230 | { |
1613 | 230 | SESSION *session; |
1614 | | // PW session do not have a loaded session and can not be an audit |
1615 | | // session either. Skip it. |
1616 | 230 | if(s_sessionHandles[i] == TPM_RS_PW) continue; |
1617 | 0 | session = SessionGet(s_sessionHandles[i]); |
1618 | | // If a session is used for audit |
1619 | 0 | if(s_attributes[i].audit == SET) |
1620 | 0 | { |
1621 | | // An audit session has been found |
1622 | 0 | 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 | 0 | if( session->attributes.isAudit == CLEAR |
1627 | 0 | || s_attributes[i].auditReset == SET |
1628 | 0 | ) |
1629 | 0 | { |
1630 | 0 | InitAuditSession(session); |
1631 | 0 | g_exclusiveAuditSession = auditSession; |
1632 | 0 | } |
1633 | 0 | else |
1634 | 0 | { |
1635 | | // Check if the audit session is the current exclusive audit |
1636 | | // session and, if not, clear previous exclusive audit session. |
1637 | 0 | if(g_exclusiveAuditSession != auditSession) |
1638 | 0 | g_exclusiveAuditSession = TPM_RH_UNASSIGNED; |
1639 | 0 | } |
1640 | | // Report audit session exclusivity. |
1641 | 0 | if(g_exclusiveAuditSession == auditSession) |
1642 | 0 | { |
1643 | 0 | s_attributes[i].auditExclusive = SET; |
1644 | 0 | } |
1645 | 0 | else |
1646 | 0 | { |
1647 | 0 | s_attributes[i].auditExclusive = CLEAR; |
1648 | 0 | } |
1649 | | // Extend audit log. |
1650 | 0 | Audit(session, commandCode, resParmBufferSize, resParmBuffer); |
1651 | 0 | } |
1652 | 0 | } |
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 | 6.77k | if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(commandCode)) |
1657 | 1.13k | { |
1658 | 1.13k | g_exclusiveAuditSession = TPM_RH_UNASSIGNED; |
1659 | 1.13k | } |
1660 | 6.77k | return; |
1661 | 6.77k | } |
1662 | | // |
1663 | | // |
1664 | | // ComputeResponseHMAC() |
1665 | | // |
1666 | | // Function to compute HMAC for authorization session in a response. |
1667 | | // |
1668 | | static void |
1669 | | ComputeResponseHMAC( |
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 | 0 | { |
1679 | 0 | TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2)); |
1680 | 0 | TPM2B_KEY key; // HMAC key |
1681 | 0 | BYTE marshalBuffer[sizeof(TPMA_SESSION)]; |
1682 | 0 | BYTE *buffer; |
1683 | 0 | INT32 bufferSize; |
1684 | 0 | UINT32 marshalSize; |
1685 | 0 | HMAC_STATE hmacState; |
1686 | 0 | TPM2B_DIGEST rp_hash; |
1687 | | // |
1688 | | // Compute rpHash. |
1689 | 0 | ComputeRpHash(session->authHashAlg, commandCode, resParmBufferSize, |
1690 | 0 | resParmBuffer, &rp_hash); |
1691 | | // Generate HMAC key |
1692 | 0 | 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 | 0 | if( s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED |
1697 | 0 | && !( HandleGetType(s_sessionHandles[sessionIndex]) |
1698 | 0 | == TPM_HT_POLICY_SESSION |
1699 | 0 | && session->attributes.isAuthValueNeeded == CLEAR) |
1700 | 0 | && !session->attributes.requestWasBound) |
1701 | 0 | { |
1702 | 0 | pAssert((sizeof(AUTH_VALUE) + key.t.size) <= sizeof(key.t.buffer)); |
1703 | 0 | key.t.size = key.t.size + |
1704 | 0 | EntityGetAuthValue(s_associatedHandles[sessionIndex], |
1705 | 0 | (AUTH_VALUE *)&key.t.buffer[key.t.size]); |
1706 | 0 | } |
1707 | | // if the HMAC key size for a policy session is 0, the response HMAC is |
1708 | | // computed according to the input HMAC |
1709 | 0 | if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION |
1710 | 0 | && key.t.size == 0 |
1711 | 0 | && s_inputAuthValues[sessionIndex].t.size == 0) |
1712 | 0 | { |
1713 | 0 | hmac->t.size = 0; |
1714 | 0 | return; |
1715 | 0 | } |
1716 | | // Start HMAC computation. |
1717 | 0 | hmac->t.size = CryptStartHMAC2B(session->authHashAlg, &key.b, &hmacState); |
1718 | | // Add hash components. |
1719 | 0 | CryptUpdateDigest2B(&hmacState, &rp_hash.b); |
1720 | 0 | CryptUpdateDigest2B(&hmacState, &nonceTPM->b); |
1721 | 0 | CryptUpdateDigest2B(&hmacState, &s_nonceCaller[sessionIndex].b); |
1722 | | // Add session attributes. |
1723 | 0 | buffer = marshalBuffer; |
1724 | 0 | bufferSize = sizeof(TPMA_SESSION); |
1725 | 0 | marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, &bufferSize); |
1726 | 0 | CryptUpdateDigest(&hmacState, marshalSize, marshalBuffer); |
1727 | | // Finalize HMAC. |
1728 | 0 | CryptCompleteHMAC2B(&hmacState, &hmac->b); |
1729 | 0 | return; |
1730 | 0 | } |
1731 | | // |
1732 | | // |
1733 | | // BuildSingleResponseAuth() |
1734 | | // |
1735 | | // Function to compute response for an authorization session. |
1736 | | // |
1737 | | static void |
1738 | | BuildSingleResponseAuth( |
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 | 230 | { |
1747 | | // For password authorization, field is empty. |
1748 | 230 | if(s_sessionHandles[sessionIndex] == TPM_RS_PW) |
1749 | 230 | { |
1750 | 230 | auth->t.size = 0; |
1751 | 230 | } |
1752 | 0 | else |
1753 | 0 | { |
1754 | | // Fill in policy/HMAC based session response. |
1755 | 0 | SESSION *session = SessionGet(s_sessionHandles[sessionIndex]); |
1756 | | // If the session is a policy session with isPasswordNeeded SET, the auth |
1757 | | // field is empty. |
1758 | 0 | if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION |
1759 | 0 | && session->attributes.isPasswordNeeded == SET) |
1760 | 0 | auth->t.size = 0; |
1761 | 0 | else |
1762 | | // Compute response HMAC. |
1763 | 0 | ComputeResponseHMAC(sessionIndex, |
1764 | 0 | session, |
1765 | 0 | commandCode, |
1766 | 0 | &session->nonceTPM, |
1767 | 0 | resParmBufferSize, |
1768 | 0 | resParmBuffer, |
1769 | 0 | auth); |
1770 | 0 | } |
1771 | 230 | return; |
1772 | 230 | } |
1773 | | // |
1774 | | // |
1775 | | // UpdateTPMNonce() |
1776 | | // |
1777 | | // Updates TPM nonce in both internal session or response if applicable. |
1778 | | // |
1779 | | static void |
1780 | | UpdateTPMNonce( |
1781 | | UINT16 noncesSize, // IN: number of elements in 'nonces' array |
1782 | | TPM2B_NONCE nonces[] // OUT: nonceTPM |
1783 | | ) |
1784 | 230 | { |
1785 | 230 | UINT32 i; |
1786 | 230 | pAssert(noncesSize >= s_sessionNum); |
1787 | 460 | for(i = 0; i < s_sessionNum; i++) |
1788 | 230 | { |
1789 | 230 | SESSION *session; |
1790 | | // For PW session, nonce is 0. |
1791 | 230 | if(s_sessionHandles[i] == TPM_RS_PW) |
1792 | 230 | { |
1793 | 230 | nonces[i].t.size = 0; |
1794 | 230 | continue; |
1795 | 230 | } |
1796 | 0 | session = SessionGet(s_sessionHandles[i]); |
1797 | | // Update nonceTPM in both internal session and response. |
1798 | 0 | CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer); |
1799 | 0 | nonces[i] = session->nonceTPM; |
1800 | 0 | } |
1801 | 230 | return; |
1802 | 230 | } |
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 | | // |
1813 | | static void |
1814 | | UpdateInternalSession( |
1815 | | void |
1816 | | ) |
1817 | 230 | { |
1818 | 230 | UINT32 i; |
1819 | 460 | for(i = 0; i < s_sessionNum; i++) |
1820 | 230 | { |
1821 | | // For PW session, no update. |
1822 | 230 | if(s_sessionHandles[i] == TPM_RS_PW) continue; |
1823 | 0 | if(s_attributes[i].continueSession == CLEAR) |
1824 | 0 | { |
1825 | | // Close internal session. |
1826 | 0 | SessionFlush(s_sessionHandles[i]); |
1827 | 0 | } |
1828 | 0 | else |
1829 | 0 | { |
1830 | | // If nonce is rolling in a policy session, the policy related data |
1831 | | // will be re-initialized. |
1832 | 0 | if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION) |
1833 | 0 | { |
1834 | 0 | SESSION *session = SessionGet(s_sessionHandles[i]); |
1835 | | // When the nonce rolls it starts a new timing interval for the |
1836 | | // policy session. |
1837 | 0 | SessionResetPolicyData(session); |
1838 | 0 | session->startTime = go.clock; |
1839 | 0 | } |
1840 | 0 | } |
1841 | 0 | } |
1842 | 230 | return; |
1843 | 230 | } |
1844 | | // |
1845 | | // |
1846 | | // BuildResponseSession() |
1847 | | // |
1848 | | // Function to build Session buffer in a response. |
1849 | | // |
1850 | | void |
1851 | | BuildResponseSession( |
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 | 6.77k | { |
1859 | 6.77k | BYTE *resParmBuffer; |
1860 | 6.77k | INT32 bufferSize; |
1861 | 6.77k | TPM2B_NONCE responseNonces[MAX_SESSION_NUM]; |
1862 | | // Compute response parameter buffer start. |
1863 | 6.77k | resParmBuffer = MemoryGetResponseBuffer(commandCode) + sizeof(TPM_ST) + |
1864 | 6.77k | sizeof(UINT32) + sizeof(TPM_RC) + resHandleSize; |
1865 | 6.77k | bufferSize = MAX_RESPONSE_SIZE - sizeof(TPM_ST) - sizeof(UINT32) - |
1866 | 6.77k | sizeof(TPM_RC) - resHandleSize; |
1867 | | // For TPM_ST_SESSIONS, there is parameterSize field. |
1868 | 6.77k | if(tag == TPM_ST_SESSIONS) { |
1869 | 230 | resParmBuffer += sizeof(UINT32); |
1870 | 230 | bufferSize -= sizeof(UINT32); |
1871 | 230 | } |
1872 | | // Session nonce should be updated before parameter encryption |
1873 | 6.77k | if(tag == TPM_ST_SESSIONS) |
1874 | 230 | { |
1875 | 230 | 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 | 230 | if(s_encryptSessionIndex != UNDEFINED_INDEX) |
1884 | 0 | { |
1885 | 0 | UINT32 size; |
1886 | 0 | TPM2B_AUTH extraKey; |
1887 | | // Get size of the leading size field |
1888 | 0 | if( s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED |
1889 | 0 | && IsAuthValueAvailable(s_associatedHandles[s_encryptSessionIndex], |
1890 | 0 | commandCode, s_encryptSessionIndex) |
1891 | 0 | ) |
1892 | 0 | { |
1893 | 0 | extraKey.b.size = |
1894 | 0 | EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex], |
1895 | 0 | &extraKey.t.buffer); |
1896 | 0 | } |
1897 | 0 | else |
1898 | 0 | { |
1899 | 0 | extraKey.b.size = 0; |
1900 | 0 | } |
1901 | 0 | size = EncryptSize(commandCode); |
1902 | 0 | CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex], |
1903 | 0 | &s_nonceCaller[s_encryptSessionIndex].b, |
1904 | 0 | bufferSize, |
1905 | 0 | (UINT16)size, |
1906 | 0 | &extraKey, |
1907 | 0 | resParmBuffer); |
1908 | 0 | } |
1909 | 230 | } |
1910 | | // Audit session should be updated first regardless of the tag. |
1911 | | // A command with no session may trigger a change of the exclusivity state. |
1912 | 6.77k | UpdateAuditSessionStatus(commandCode, resParmSize, resParmBuffer); |
1913 | | // Audit command. |
1914 | 6.77k | CommandAudit(commandCode, resParmSize, resParmBuffer); |
1915 | | // Process command with sessions. |
1916 | 6.77k | if(tag == TPM_ST_SESSIONS) |
1917 | 230 | { |
1918 | 230 | UINT32 i; |
1919 | 230 | BYTE *buffer; |
1920 | 230 | TPM2B_DIGEST responseAuths[MAX_SESSION_NUM]; |
1921 | 230 | pAssert(s_sessionNum > 0); |
1922 | | // Iterate over each session in the command session area, and create |
1923 | | // corresponding sessions for response. |
1924 | 460 | for(i = 0; i < s_sessionNum; i++) |
1925 | 230 | { |
1926 | 230 | BuildSingleResponseAuth( |
1927 | 230 | i, |
1928 | 230 | commandCode, |
1929 | 230 | resParmSize, |
1930 | 230 | resParmBuffer, |
1931 | 230 | &responseAuths[i]); |
1932 | | // Make sure that continueSession is SET on any Password session. |
1933 | | // This makes it marginally easier for the management software |
1934 | | // to keep track of the closed sessions. |
1935 | 230 | if( s_attributes[i].continueSession == CLEAR |
1936 | 230 | && s_sessionHandles[i] == TPM_RS_PW) |
1937 | 143 | { |
1938 | 143 | s_attributes[i].continueSession = SET; |
1939 | 143 | } |
1940 | 230 | } |
1941 | | // Assemble Response Sessions. |
1942 | 230 | *resSessionSize = 0; |
1943 | 230 | buffer = resParmBuffer + resParmSize; |
1944 | 230 | bufferSize -= resParmSize; |
1945 | 460 | for(i = 0; i < s_sessionNum; i++) |
1946 | 230 | { |
1947 | 230 | *resSessionSize += TPM2B_NONCE_Marshal(&responseNonces[i], |
1948 | 230 | &buffer, &bufferSize); |
1949 | 230 | *resSessionSize += TPMA_SESSION_Marshal(&s_attributes[i], |
1950 | 230 | &buffer, &bufferSize); |
1951 | 230 | *resSessionSize += TPM2B_DIGEST_Marshal(&responseAuths[i], |
1952 | 230 | &buffer, &bufferSize); |
1953 | 230 | } |
1954 | | // Update internal sessions after completing response buffer computation. |
1955 | 230 | UpdateInternalSession(); |
1956 | 230 | } |
1957 | 6.54k | else |
1958 | 6.54k | { |
1959 | | // Process command with no session. |
1960 | 6.54k | *resSessionSize = 0; |
1961 | 6.54k | } |
1962 | 6.77k | return; |
1963 | 6.77k | } |