/src/libtpms/src/tpm2/SessionProcess.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* Process the Authorization Sessions */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* */ |
7 | | /* Licenses and Notices */ |
8 | | /* */ |
9 | | /* 1. Copyright Licenses: */ |
10 | | /* */ |
11 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
12 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
13 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
14 | | /* derivative works, distribute, display and perform the Source Code and */ |
15 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
16 | | /* */ |
17 | | /* - The TCG grants to the user of the other parts of the specification */ |
18 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
19 | | /* display, and perform the specification solely for the purpose of */ |
20 | | /* developing products based on such documents. */ |
21 | | /* */ |
22 | | /* 2. Source Code Distribution Conditions: */ |
23 | | /* */ |
24 | | /* - Redistributions of Source Code must retain the above copyright licenses, */ |
25 | | /* this list of conditions and the following disclaimers. */ |
26 | | /* */ |
27 | | /* - Redistributions in binary form must reproduce the above copyright */ |
28 | | /* licenses, this list of conditions and the following disclaimers in the */ |
29 | | /* documentation and/or other materials provided with the distribution. */ |
30 | | /* */ |
31 | | /* 3. Disclaimers: */ |
32 | | /* */ |
33 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
34 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
35 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
36 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
37 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
38 | | /* information on specification licensing rights available through TCG */ |
39 | | /* membership agreements. */ |
40 | | /* */ |
41 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
42 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
43 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
44 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
45 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
46 | | /* */ |
47 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
48 | | /* liability, including liability for infringement of any proprietary */ |
49 | | /* rights, relating to use of information in this specification and to the */ |
50 | | /* implementation of this specification, and TCG disclaims all liability for */ |
51 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
52 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
53 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
54 | | /* arising in any way out of use or reliance upon this specification or any */ |
55 | | /* information herein. */ |
56 | | /* */ |
57 | | /* (c) Copyright IBM Corp. and others, 2016 - 2023 */ |
58 | | /* */ |
59 | | /********************************************************************************/ |
60 | | |
61 | | //** Introduction |
62 | | // This file contains the subsystem that process the authorization sessions |
63 | | // including implementation of the Dictionary Attack logic. ExecCommand() uses |
64 | | // ParseSessionBuffer() to process the authorization session area of a command and |
65 | | // BuildResponseSession() to create the authorization session area of a response. |
66 | | |
67 | | //** Includes and Data Definitions |
68 | | |
69 | | #define SESSION_PROCESS_C |
70 | | |
71 | | #include "Tpm.h" |
72 | | #include "ACT.h" |
73 | | #include "Marshal.h" |
74 | | |
75 | | // |
76 | | //** Authorization Support Functions |
77 | | // |
78 | | |
79 | | //*** IsDAExempted() |
80 | | // This function indicates if a handle is exempted from DA logic. |
81 | | // A handle is exempted if it is: |
82 | | // a) a primary seed handle; |
83 | | // b) an object with noDA bit SET; |
84 | | // c) an NV Index with TPMA_NV_NO_DA bit SET; or |
85 | | // d) a PCR handle. |
86 | | // |
87 | | // Return Type: BOOL |
88 | | // TRUE(1) handle is exempted from DA logic |
89 | | // FALSE(0) handle is not exempted from DA logic |
90 | | BOOL IsDAExempted(TPM_HANDLE handle // IN: entity handle |
91 | | ) |
92 | 1.63k | { |
93 | 1.63k | BOOL result = FALSE; |
94 | | // |
95 | 1.63k | switch(HandleGetType(handle)) |
96 | 1.63k | { |
97 | 1.51k | case TPM_HT_PERMANENT: |
98 | | // All permanent handles, other than TPM_RH_LOCKOUT, are exempt from |
99 | | // DA protection. |
100 | 1.51k | result = (handle != TPM_RH_LOCKOUT); |
101 | 1.51k | break; |
102 | | // When this function is called, a persistent object will have been loaded |
103 | | // into an object slot and assigned a transient handle. |
104 | 0 | case TPM_HT_TRANSIENT: |
105 | 0 | { |
106 | 0 | TPMA_OBJECT attributes = ObjectGetPublicAttributes(handle); |
107 | 0 | result = IS_ATTRIBUTE(attributes, TPMA_OBJECT, noDA); |
108 | 0 | break; |
109 | 0 | } |
110 | 0 | case TPM_HT_NV_INDEX: |
111 | 0 | { |
112 | 0 | NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL); |
113 | 0 | result = IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, NO_DA); |
114 | 0 | break; |
115 | 0 | } |
116 | 125 | case TPM_HT_PCR: |
117 | | // PCRs are always exempted from DA. |
118 | 125 | result = TRUE; |
119 | 125 | break; |
120 | 0 | default: |
121 | 0 | break; |
122 | 1.63k | } |
123 | 1.63k | return result; |
124 | 1.63k | } |
125 | | |
126 | | //*** IncrementLockout() |
127 | | // This function is called after an authorization failure that involves use of |
128 | | // an authValue. If the entity referenced by the handle is not exempt from DA |
129 | | // protection, then the failedTries counter will be incremented. |
130 | | // |
131 | | // Return Type: TPM_RC |
132 | | // TPM_RC_AUTH_FAIL authorization failure that caused DA lockout to increment |
133 | | // TPM_RC_BAD_AUTH authorization failure did not cause DA lockout to |
134 | | // increment |
135 | | static TPM_RC IncrementLockout(UINT32 sessionIndex) |
136 | 9 | { |
137 | 9 | TPM_HANDLE handle = s_associatedHandles[sessionIndex]; |
138 | 9 | TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex]; |
139 | 9 | SESSION* session = NULL; |
140 | | // |
141 | | // Don't increment lockout unless the handle associated with the session |
142 | | // is DA protected or the session is bound to a DA protected entity. |
143 | 9 | if(sessionHandle == TPM_RS_PW) |
144 | 9 | { |
145 | 9 | if(IsDAExempted(handle)) |
146 | 6 | return TPM_RC_BAD_AUTH; |
147 | 9 | } |
148 | 0 | else |
149 | 0 | { |
150 | 0 | session = SessionGet(sessionHandle); |
151 | | // If the session is bound to lockout, then use that as the relevant |
152 | | // handle. This means that an authorization failure with a bound session |
153 | | // bound to lockoutAuth will take precedence over any other |
154 | | // lockout check |
155 | 0 | if(session->attributes.isLockoutBound == SET) |
156 | 0 | handle = TPM_RH_LOCKOUT; |
157 | 0 | if(session->attributes.isDaBound == CLEAR |
158 | 0 | && (IsDAExempted(handle) || session->attributes.includeAuth == CLEAR)) |
159 | | // If the handle was changed to TPM_RH_LOCKOUT, this will not return |
160 | | // TPM_RC_BAD_AUTH |
161 | 0 | return TPM_RC_BAD_AUTH; |
162 | 0 | } |
163 | 3 | if(handle == TPM_RH_LOCKOUT) |
164 | 3 | { |
165 | 3 | pAssert(gp.lockOutAuthEnabled == TRUE); |
166 | | |
167 | | // lockout is no longer enabled |
168 | 3 | gp.lockOutAuthEnabled = FALSE; |
169 | | |
170 | | // For TPM_RH_LOCKOUT, if lockoutRecovery is 0, no need to update NV since |
171 | | // the lockout authorization will be reset at startup. |
172 | 3 | if(gp.lockoutRecovery != 0) |
173 | 3 | { |
174 | 3 | if(NV_IS_AVAILABLE) |
175 | | // Update NV. |
176 | 3 | NV_SYNC_PERSISTENT(lockOutAuthEnabled); |
177 | 0 | else |
178 | | // No NV access for now. Put the TPM in pending mode. |
179 | 0 | s_DAPendingOnNV = TRUE; |
180 | 3 | } |
181 | 3 | } |
182 | 0 | else |
183 | 0 | { |
184 | 0 | if(gp.recoveryTime != 0) |
185 | 0 | { |
186 | 0 | gp.failedTries++; |
187 | 0 | if(NV_IS_AVAILABLE) |
188 | | // Record changes to NV. NvWrite will SET g_updateNV |
189 | 0 | NV_SYNC_PERSISTENT(failedTries); |
190 | 0 | else |
191 | | // No NV access for now. Put the TPM in pending mode. |
192 | 0 | s_DAPendingOnNV = TRUE; |
193 | 0 | } |
194 | 0 | } |
195 | | // Register a DA failure and reset the timers. |
196 | 3 | DARegisterFailure(handle); |
197 | | |
198 | 3 | return TPM_RC_AUTH_FAIL; |
199 | 3 | } |
200 | | |
201 | | //*** IsSessionBindEntity() |
202 | | // This function indicates if the entity associated with the handle is the entity, |
203 | | // to which this session is bound. The binding would occur by making the "bind" |
204 | | // parameter in TPM2_StartAuthSession() not equal to TPM_RH_NULL. The binding only |
205 | | // occurs if the session is an HMAC session. The bind value is a combination of |
206 | | // the Name and the authValue of the entity. |
207 | | // |
208 | | // Return Type: BOOL |
209 | | // TRUE(1) handle points to the session start entity |
210 | | // FALSE(0) handle does not point to the session start entity |
211 | | static BOOL IsSessionBindEntity( |
212 | | TPM_HANDLE associatedHandle, // IN: handle to be authorized |
213 | | SESSION* session // IN: associated session |
214 | | ) |
215 | 0 | { |
216 | 0 | TPM2B_NAME entity; // The bind value for the entity |
217 | | // |
218 | | // If the session is not bound, return FALSE. |
219 | 0 | if(session->attributes.isBound) |
220 | 0 | { |
221 | | // Compute the bind value for the entity. |
222 | 0 | SessionComputeBoundEntity(associatedHandle, &entity); |
223 | | |
224 | | // Compare to the bind value in the session. |
225 | 0 | return MemoryEqual2B(&entity.b, &session->u1.boundEntity.b); |
226 | 0 | } |
227 | 0 | return FALSE; |
228 | 0 | } |
229 | | |
230 | | //*** IsPolicySessionRequired() |
231 | | // Checks if a policy session is required for a command. If a command requires |
232 | | // DUP or ADMIN role authorization, then the handle that requires that role is the |
233 | | // first handle in the command. This simplifies this checking. If a new command |
234 | | // is created that requires multiple ADMIN role authorizations, then it will |
235 | | // have to be special-cased in this function. |
236 | | // A policy session is required if: |
237 | | // a) the command requires the DUP role; |
238 | | // b) the command requires the ADMIN role and the authorized entity |
239 | | // is an object and its adminWithPolicy bit is SET; |
240 | | // c) the command requires the ADMIN role and the authorized entity |
241 | | // is a permanent handle or an NV Index; or |
242 | | // d) the authorized entity is a PCR belonging to a policy group, and |
243 | | // has its policy initialized |
244 | | // Return Type: BOOL |
245 | | // TRUE(1) policy session is required |
246 | | // FALSE(0) policy session is not required |
247 | | static BOOL IsPolicySessionRequired(COMMAND_INDEX commandIndex, // IN: command index |
248 | | UINT32 sessionIndex // IN: session index |
249 | | ) |
250 | 1.61k | { |
251 | 1.61k | AUTH_ROLE role = CommandAuthRole(commandIndex, sessionIndex); |
252 | 1.61k | TPM_HT type = HandleGetType(s_associatedHandles[sessionIndex]); |
253 | | // |
254 | 1.61k | if(role == AUTH_DUP) |
255 | 0 | return TRUE; |
256 | 1.61k | if(role == AUTH_ADMIN) |
257 | 0 | { |
258 | | // We allow an exception for ADMIN role in a transient object. If the object |
259 | | // allows ADMIN role actions with authorization, then policy is not |
260 | | // required. For all other cases, there is no way to override the command |
261 | | // requirement that a policy be used |
262 | 0 | if(type == TPM_HT_TRANSIENT) |
263 | 0 | { |
264 | 0 | OBJECT* object = HandleToObject(s_associatedHandles[sessionIndex]); |
265 | |
|
266 | 0 | if(!IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, adminWithPolicy)) |
267 | 0 | return FALSE; |
268 | 0 | } |
269 | 0 | return TRUE; |
270 | 0 | } |
271 | | |
272 | 1.61k | if(type == TPM_HT_PCR) |
273 | 117 | { |
274 | 117 | if(PCRPolicyIsAvailable(s_associatedHandles[sessionIndex])) |
275 | 0 | { |
276 | 0 | TPM2B_DIGEST policy; |
277 | 0 | TPMI_ALG_HASH policyAlg; |
278 | 0 | policyAlg = PCRGetAuthPolicy(s_associatedHandles[sessionIndex], &policy); |
279 | 0 | if(policyAlg != TPM_ALG_NULL) |
280 | 0 | return TRUE; |
281 | 0 | } |
282 | 117 | } |
283 | 1.61k | return FALSE; |
284 | 1.61k | } |
285 | | |
286 | | //*** IsAuthValueAvailable() |
287 | | // This function indicates if authValue is available and allowed for USER role |
288 | | // authorization of an entity. |
289 | | // |
290 | | // This function is similar to IsAuthPolicyAvailable() except that it does not |
291 | | // check the size of the authValue as IsAuthPolicyAvailable() does (a null |
292 | | // authValue is a valid authorization, but a null policy is not a valid policy). |
293 | | // |
294 | | // This function does not check that the handle reference is valid or if the entity |
295 | | // is in an enabled hierarchy. Those checks are assumed to have been performed |
296 | | // during the handle unmarshaling. |
297 | | // |
298 | | // Return Type: BOOL |
299 | | // TRUE(1) authValue is available |
300 | | // FALSE(0) authValue is not available |
301 | | static BOOL IsAuthValueAvailable(TPM_HANDLE handle, // IN: handle of entity |
302 | | COMMAND_INDEX commandIndex, // IN: command index |
303 | | UINT32 sessionIndex // IN: session index |
304 | | ) |
305 | 1.61k | { |
306 | 1.61k | BOOL result = FALSE; |
307 | | // |
308 | 1.61k | switch(HandleGetType(handle)) |
309 | 1.61k | { |
310 | 1.49k | case TPM_HT_PERMANENT: |
311 | 1.49k | switch(handle) |
312 | 1.49k | { |
313 | | // At this point hierarchy availability has already been |
314 | | // checked so primary seed handles are always available here |
315 | 597 | case TPM_RH_OWNER: |
316 | 853 | case TPM_RH_ENDORSEMENT: |
317 | 1.20k | case TPM_RH_PLATFORM: |
318 | | #if VENDOR_PERMANENT_AUTH_ENABLED == YES |
319 | | // This vendor defined handle associated with the |
320 | | // manufacturer's shared secret |
321 | | case VENDOR_PERMANENT_AUTH_HANDLE: |
322 | | #endif |
323 | | // The DA checking has been performed on LockoutAuth but we |
324 | | // bypass the DA logic if we are using lockout policy. The |
325 | | // policy would allow execution to continue an lockoutAuth |
326 | | // could be used, even if direct use of lockoutAuth is disabled |
327 | 1.21k | case TPM_RH_LOCKOUT: |
328 | | // NullAuth is always available. |
329 | 1.49k | case TPM_RH_NULL: |
330 | 1.49k | result = TRUE; |
331 | 1.49k | break; |
332 | | |
333 | | #ifndef __ACT_DISABLED // libtpms changed |
334 | | FOR_EACH_ACT(CASE_ACT_HANDLE) |
335 | | { |
336 | | // The ACT auth value is not available if the platform is disabled |
337 | | result = g_phEnable == SET; |
338 | | break; |
339 | | } |
340 | | #endif // ACT_SUPPORT |
341 | | |
342 | 0 | default: |
343 | | // Otherwise authValue is not available. |
344 | 0 | break; |
345 | 1.49k | } |
346 | 1.49k | break; |
347 | 1.49k | case TPM_HT_TRANSIENT: |
348 | | // A persistent object has already been loaded and the internal |
349 | | // handle changed. |
350 | 0 | { |
351 | 0 | OBJECT* object; |
352 | 0 | TPMA_OBJECT attributes; |
353 | | // |
354 | 0 | object = HandleToObject(handle); |
355 | 0 | attributes = object->publicArea.objectAttributes; |
356 | | |
357 | | // authValue is always available for a sequence object. |
358 | | // An alternative for this is to |
359 | | // SET_ATTRIBUTE(object->publicArea, TPMA_OBJECT, userWithAuth) when the |
360 | | // sequence is started. |
361 | 0 | if(ObjectIsSequence(object)) |
362 | 0 | { |
363 | 0 | result = TRUE; |
364 | 0 | break; |
365 | 0 | } |
366 | | // authValue is available for an object if it has its sensitive |
367 | | // portion loaded and |
368 | | // a) userWithAuth bit is SET, or |
369 | | // b) ADMIN role is required |
370 | 0 | if(object->attributes.publicOnly == CLEAR |
371 | 0 | && (IS_ATTRIBUTE(attributes, TPMA_OBJECT, userWithAuth) |
372 | 0 | || (CommandAuthRole(commandIndex, sessionIndex) == AUTH_ADMIN |
373 | 0 | && !IS_ATTRIBUTE( |
374 | 0 | attributes, TPMA_OBJECT, adminWithPolicy)))) |
375 | 0 | result = TRUE; |
376 | 0 | } |
377 | 0 | break; |
378 | 0 | case TPM_HT_NV_INDEX: |
379 | | // NV Index. |
380 | 0 | { |
381 | 0 | NV_REF locator; |
382 | 0 | NV_INDEX* nvIndex = NvGetIndexInfo(handle, &locator); |
383 | 0 | TPMA_NV nvAttributes; |
384 | | // |
385 | 0 | pAssert(nvIndex != 0); |
386 | | |
387 | 0 | nvAttributes = nvIndex->publicArea.attributes; |
388 | |
|
389 | 0 | if(IsWriteOperation(commandIndex)) |
390 | 0 | { |
391 | | // AuthWrite can't be set for a PIN index |
392 | 0 | if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHWRITE)) |
393 | 0 | result = TRUE; |
394 | 0 | } |
395 | 0 | else |
396 | 0 | { |
397 | | // A "read" operation |
398 | | // For a PIN Index, the authValue is available as long as the |
399 | | // Index has been written and the pinCount is less than pinLimit |
400 | 0 | if(IsNvPinFailIndex(nvAttributes) |
401 | 0 | || IsNvPinPassIndex(nvAttributes)) |
402 | 0 | { |
403 | 0 | NV_PIN pin; |
404 | 0 | if(!IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN)) |
405 | 0 | break; // return false |
406 | | // get the index values |
407 | 0 | pin.intVal = NvGetUINT64Data(nvIndex, locator); |
408 | 0 | if(pin.pin.pinCount < pin.pin.pinLimit) |
409 | 0 | result = TRUE; |
410 | 0 | } |
411 | | // For non-PIN Indexes, need to allow use of the authValue |
412 | 0 | else if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, AUTHREAD)) |
413 | 0 | result = TRUE; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | break; |
417 | 117 | case TPM_HT_PCR: |
418 | | // PCR handle. |
419 | | // authValue is always allowed for PCR |
420 | 117 | result = TRUE; |
421 | 117 | break; |
422 | 0 | default: |
423 | | // Otherwise, authValue is not available |
424 | 0 | break; |
425 | 1.61k | } |
426 | 1.61k | return result; |
427 | 1.61k | } |
428 | | |
429 | | //*** IsAuthPolicyAvailable() |
430 | | // This function indicates if an authPolicy is available and allowed. |
431 | | // |
432 | | // This function does not check that the handle reference is valid or if the entity |
433 | | // is in an enabled hierarchy. Those checks are assumed to have been performed |
434 | | // during the handle unmarshaling. |
435 | | // |
436 | | // Return Type: BOOL |
437 | | // TRUE(1) authPolicy is available |
438 | | // FALSE(0) authPolicy is not available |
439 | | static BOOL IsAuthPolicyAvailable(TPM_HANDLE handle, // IN: handle of entity |
440 | | COMMAND_INDEX commandIndex, // IN: command index |
441 | | UINT32 sessionIndex // IN: session index |
442 | | ) |
443 | 0 | { |
444 | 0 | BOOL result = FALSE; |
445 | | // |
446 | 0 | switch(HandleGetType(handle)) |
447 | 0 | { |
448 | 0 | case TPM_HT_PERMANENT: |
449 | 0 | switch(handle) |
450 | 0 | { |
451 | | // At this point hierarchy availability has already been checked. |
452 | 0 | case TPM_RH_OWNER: |
453 | 0 | if(gp.ownerPolicy.t.size != 0) |
454 | 0 | result = TRUE; |
455 | 0 | break; |
456 | 0 | case TPM_RH_ENDORSEMENT: |
457 | 0 | if(gp.endorsementPolicy.t.size != 0) |
458 | 0 | result = TRUE; |
459 | 0 | break; |
460 | 0 | case TPM_RH_PLATFORM: |
461 | 0 | if(gc.platformPolicy.t.size != 0) |
462 | 0 | result = TRUE; |
463 | 0 | break; |
464 | 0 | #if ACT_SUPPORT || 1 // libtpms changed |
465 | | |
466 | 0 | # define ACT_GET_POLICY(N) \ |
467 | 0 | case TPM_RH_ACT_##N: \ |
468 | 0 | if(go.ACT_##N.authPolicy.t.size != 0) \ |
469 | 0 | result = TRUE; \ |
470 | 0 | break; |
471 | | |
472 | 0 | FOR_EACH_ACT(ACT_GET_POLICY) |
473 | 0 | #endif // ACT_SUPPORT |
474 | | |
475 | 0 | case TPM_RH_LOCKOUT: |
476 | 0 | if(gp.lockoutPolicy.t.size != 0) |
477 | 0 | result = TRUE; |
478 | 0 | break; |
479 | 0 | default: |
480 | 0 | break; |
481 | 0 | } |
482 | 0 | break; |
483 | 0 | case TPM_HT_TRANSIENT: |
484 | 0 | { |
485 | | // Object handle. |
486 | | // An evict object would already have been loaded and given a |
487 | | // transient object handle by this point. |
488 | 0 | OBJECT* object = HandleToObject(handle); |
489 | | // Policy authorization is not available for an object with only |
490 | | // public portion loaded. |
491 | 0 | if(object->attributes.publicOnly == CLEAR) |
492 | 0 | { |
493 | | // Policy authorization is always available for an object but |
494 | | // is never available for a sequence. |
495 | 0 | if(!ObjectIsSequence(object)) |
496 | 0 | result = TRUE; |
497 | 0 | } |
498 | 0 | break; |
499 | 0 | } |
500 | 0 | case TPM_HT_NV_INDEX: |
501 | | // An NV Index. |
502 | 0 | { |
503 | 0 | NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL); |
504 | 0 | TPMA_NV nvAttributes = nvIndex->publicArea.attributes; |
505 | | // |
506 | | // If the policy size is not zero, check if policy can be used. |
507 | 0 | if(nvIndex->publicArea.authPolicy.t.size != 0) |
508 | 0 | { |
509 | | // If policy session is required for this handle, always |
510 | | // uses policy regardless of the attributes bit setting |
511 | 0 | if(IsPolicySessionRequired(commandIndex, sessionIndex)) |
512 | 0 | result = TRUE; |
513 | | // Otherwise, the presence of the policy depends on the NV |
514 | | // attributes. |
515 | 0 | else if(IsWriteOperation(commandIndex)) |
516 | 0 | { |
517 | 0 | if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYWRITE)) |
518 | 0 | result = TRUE; |
519 | 0 | } |
520 | 0 | else |
521 | 0 | { |
522 | 0 | if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, POLICYREAD)) |
523 | 0 | result = TRUE; |
524 | 0 | } |
525 | 0 | } |
526 | 0 | } |
527 | 0 | break; |
528 | 0 | case TPM_HT_PCR: |
529 | | // PCR handle. |
530 | 0 | if(PCRPolicyIsAvailable(handle)) |
531 | 0 | result = TRUE; |
532 | 0 | break; |
533 | 0 | default: |
534 | 0 | break; |
535 | 0 | } |
536 | 0 | return result; |
537 | 0 | } |
538 | | |
539 | | //** Session Parsing Functions |
540 | | |
541 | | //*** ClearCpRpHashes() |
542 | | void ClearCpRpHashes(COMMAND* command) |
543 | 12.1k | { |
544 | | // The macros expand according to the implemented hash algorithms. An IDE may |
545 | | // complain that COMMAND does not contain SHA1CpHash or SHA1RpHash because of the |
546 | | // complexity of the macro expansion where the data space is defined; but, if SHA1 |
547 | | // is implemented, it actually does and the compiler is happy. |
548 | 48.6k | #define CLEAR_CP_HASH(HASH, Hash) command->Hash##CpHash.b.size = 0; |
549 | 48.6k | FOR_EACH_HASH(CLEAR_CP_HASH) |
550 | 48.6k | #define CLEAR_RP_HASH(HASH, Hash) command->Hash##RpHash.b.size = 0; |
551 | 48.6k | FOR_EACH_HASH(CLEAR_RP_HASH) |
552 | 12.1k | } |
553 | | |
554 | | //*** GetCpHashPointer() |
555 | | // Function to get a pointer to the cpHash of the command |
556 | | static TPM2B_DIGEST* GetCpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg) |
557 | 309 | { |
558 | 309 | TPM2B_DIGEST* retVal; |
559 | | // |
560 | | // Define the macro that will expand for each implemented algorithm in the switch |
561 | | // statement below. |
562 | 309 | #define GET_CP_HASH_POINTER(HASH, Hash) \ |
563 | 309 | case ALG_##HASH##_VALUE: \ |
564 | 309 | retVal = (TPM2B_DIGEST*)&command->Hash##CpHash; \ |
565 | 309 | break; |
566 | | |
567 | 309 | switch(hashAlg) |
568 | 309 | { |
569 | | // For each implemented hash, this will expand as defined above |
570 | | // by GET_CP_HASH_POINTER. Your IDE may complain that |
571 | | // 'struct "COMMAND" has no field "SHA1CpHash"' but the compiler says |
572 | | // it does, so... |
573 | 309 | FOR_EACH_HASH(GET_CP_HASH_POINTER) |
574 | 0 | default: |
575 | 0 | retVal = NULL; |
576 | 0 | break; |
577 | 309 | } |
578 | 309 | return retVal; |
579 | 309 | } |
580 | | |
581 | | //*** GetRpHashPointer() |
582 | | // Function to get a pointer to the RpHash of the command |
583 | | static TPM2B_DIGEST* GetRpHashPointer(COMMAND* command, TPMI_ALG_HASH hashAlg) |
584 | 126 | { |
585 | 126 | TPM2B_DIGEST* retVal; |
586 | | // |
587 | | // Define the macro that will expand for each implemented algorithm in the switch |
588 | | // statement below. |
589 | 126 | #define GET_RP_HASH_POINTER(HASH, Hash) \ |
590 | 126 | case ALG_##HASH##_VALUE: \ |
591 | 126 | retVal = (TPM2B_DIGEST*)&command->Hash##RpHash; \ |
592 | 126 | break; |
593 | | |
594 | 126 | switch(hashAlg) |
595 | 126 | { |
596 | | // For each implemented hash, this will expand as defined above |
597 | | // by GET_RP_HASH_POINTER. Your IDE may complain that |
598 | | // 'struct "COMMAND" has no field 'SHA1RpHash'" but the compiler says |
599 | | // it does, so... |
600 | 126 | FOR_EACH_HASH(GET_RP_HASH_POINTER) |
601 | 0 | default: |
602 | 0 | retVal = NULL; |
603 | 0 | break; |
604 | 126 | } |
605 | 126 | return retVal; |
606 | 126 | } |
607 | | |
608 | | //*** ComputeCpHash() |
609 | | // This function computes the cpHash as defined in Part 2 and described in Part 1. |
610 | | static TPM2B_DIGEST* ComputeCpHash(COMMAND* command, // IN: command parsing structure |
611 | | TPMI_ALG_HASH hashAlg // IN: hash algorithm |
612 | | ) |
613 | 183 | { |
614 | 183 | UINT32 i; |
615 | 183 | HASH_STATE hashState; |
616 | 183 | TPM2B_NAME name; |
617 | 183 | TPM2B_DIGEST* cpHash; |
618 | | // |
619 | | // cpHash = hash(commandCode [ || authName1 |
620 | | // [ || authName2 |
621 | | // [ || authName 3 ]]] |
622 | | // [ || parameters]) |
623 | | // A cpHash can contain just a commandCode only if the lone session is |
624 | | // an audit session. |
625 | | // Get pointer to the hash value |
626 | 183 | cpHash = GetCpHashPointer(command, hashAlg); |
627 | 183 | if(cpHash->t.size == 0) |
628 | 183 | { |
629 | 183 | cpHash->t.size = CryptHashStart(&hashState, hashAlg); |
630 | | // Add commandCode. |
631 | 183 | CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code); |
632 | | // Add authNames for each of the handles. |
633 | 366 | for(i = 0; i < command->handleNum; i++) |
634 | 183 | CryptDigestUpdate2B(&hashState, |
635 | 183 | &EntityGetName(command->handles[i], &name)->b); |
636 | | // Add the parameters. |
637 | 183 | CryptDigestUpdate( |
638 | 183 | &hashState, command->parameterSize, command->parameterBuffer); |
639 | | // Complete the hash. |
640 | 183 | CryptHashEnd2B(&hashState, &cpHash->b); |
641 | 183 | } |
642 | 183 | return cpHash; |
643 | 183 | } |
644 | | |
645 | | //*** GetCpHash() |
646 | | // This function is used to access a precomputed cpHash. |
647 | | static TPM2B_DIGEST* GetCpHash(COMMAND* command, TPMI_ALG_HASH hashAlg) |
648 | 126 | { |
649 | 126 | TPM2B_DIGEST* cpHash = GetCpHashPointer(command, hashAlg); |
650 | | // |
651 | 126 | pAssert(cpHash->t.size != 0); |
652 | 126 | return cpHash; |
653 | 126 | } |
654 | | |
655 | | //*** CompareTemplateHash() |
656 | | // This function computes the template hash and compares it to the session |
657 | | // templateHash. It is the hash of the second parameter |
658 | | // assuming that the command is TPM2_Create(), TPM2_CreatePrimary(), or |
659 | | // TPM2_CreateLoaded() |
660 | | // Return Type: BOOL |
661 | | // TRUE(1) template hash equal to session->templateHash |
662 | | // FALSE(0) template hash not equal to session->templateHash |
663 | | static BOOL CompareTemplateHash(COMMAND* command, // IN: parsing structure |
664 | | SESSION* session // IN: session data |
665 | | ) |
666 | 0 | { |
667 | 0 | BYTE* pBuffer = command->parameterBuffer; |
668 | 0 | INT32 pSize = command->parameterSize; |
669 | 0 | TPM2B_DIGEST tHash; |
670 | 0 | UINT16 size; |
671 | | // |
672 | | // Only try this for the three commands for which it is intended |
673 | 0 | if(command->code != TPM_CC_Create && command->code != TPM_CC_CreatePrimary |
674 | 0 | #if CC_CreateLoaded |
675 | 0 | && command->code != TPM_CC_CreateLoaded |
676 | 0 | #endif |
677 | 0 | ) |
678 | 0 | return FALSE; |
679 | | // Assume that the first parameter is a TPM2B and unmarshal the size field |
680 | | // Note: this will not affect the parameter buffer and size in the calling |
681 | | // function. |
682 | 0 | if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS) |
683 | 0 | return FALSE; |
684 | | // reduce the space in the buffer. |
685 | | // NOTE: this could make pSize go negative if the parameters are not correct but |
686 | | // the unmarshaling code does not try to unmarshal if the remaining size is |
687 | | // negative. |
688 | 0 | pSize -= size; |
689 | | |
690 | | // Advance the pointer |
691 | 0 | pBuffer += size; |
692 | | |
693 | | // Get the size of what should be the template |
694 | 0 | if(UINT16_Unmarshal(&size, &pBuffer, &pSize) != TPM_RC_SUCCESS) |
695 | 0 | return FALSE; |
696 | | // See if this is reasonable |
697 | 0 | if(size > pSize) |
698 | 0 | return FALSE; |
699 | | // Hash the template data |
700 | 0 | tHash.t.size = CryptHashBlock( |
701 | 0 | session->authHashAlg, size, pBuffer, sizeof(tHash.t.buffer), tHash.t.buffer); |
702 | 0 | return (MemoryEqual2B(&session->u1.templateHash.b, &tHash.b)); |
703 | 0 | } |
704 | | |
705 | | //*** CompareNameHash() |
706 | | // This function computes the name hash and compares it to the nameHash in the |
707 | | // session data, returning true if they are equal. |
708 | | BOOL CompareNameHash(COMMAND* command, // IN: main parsing structure |
709 | | SESSION* session // IN: session structure with nameHash |
710 | | ) |
711 | 0 | { |
712 | 0 | HASH_STATE hashState; |
713 | 0 | TPM2B_DIGEST nameHash; |
714 | 0 | UINT32 i; |
715 | 0 | TPM2B_NAME name; |
716 | | // |
717 | 0 | nameHash.t.size = CryptHashStart(&hashState, session->authHashAlg); |
718 | | // Add names. |
719 | 0 | for(i = 0; i < command->handleNum; i++) |
720 | 0 | CryptDigestUpdate2B(&hashState, |
721 | 0 | &EntityGetName(command->handles[i], &name)->b); |
722 | | // Complete hash. |
723 | 0 | CryptHashEnd2B(&hashState, &nameHash.b); |
724 | | // and compare |
725 | 0 | return MemoryEqual( |
726 | 0 | session->u1.nameHash.t.buffer, nameHash.t.buffer, nameHash.t.size); |
727 | 0 | } |
728 | | |
729 | | //*** CompareParametersHash() |
730 | | // This function computes the parameters hash and compares it to the pHash in |
731 | | // the session data, returning true if they are equal. |
732 | | BOOL CompareParametersHash(COMMAND* command, // IN: main parsing structure |
733 | | SESSION* session // IN: session structure with pHash |
734 | | ) |
735 | 0 | { |
736 | 0 | HASH_STATE hashState; |
737 | 0 | TPM2B_DIGEST pHash; |
738 | | // |
739 | 0 | pHash.t.size = CryptHashStart(&hashState, session->authHashAlg); |
740 | | // Add commandCode. |
741 | 0 | CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code); |
742 | | // Add the parameters. |
743 | 0 | CryptDigestUpdate(&hashState, command->parameterSize, command->parameterBuffer); |
744 | | // Complete hash. |
745 | 0 | CryptHashEnd2B(&hashState, &pHash.b); |
746 | | // and compare |
747 | 0 | return MemoryEqual2B(&session->u1.pHash.b, &pHash.b); |
748 | 0 | } |
749 | | |
750 | | //*** CheckPWAuthSession() |
751 | | // This function validates the authorization provided in a PWAP session. It |
752 | | // compares the input value to authValue of the authorized entity. Argument |
753 | | // sessionIndex is used to get handles handle of the referenced entities from |
754 | | // s_inputAuthValues[] and s_associatedHandles[]. |
755 | | // |
756 | | // Return Type: TPM_RC |
757 | | // TPM_RC_AUTH_FAIL authorization fails and increments DA failure |
758 | | // count |
759 | | // TPM_RC_BAD_AUTH authorization fails but DA does not apply |
760 | | // |
761 | | static TPM_RC CheckPWAuthSession( |
762 | | UINT32 sessionIndex // IN: index of session to be processed |
763 | | ) |
764 | 1.61k | { |
765 | 1.61k | TPM2B_AUTH authValue; |
766 | 1.61k | TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex]; |
767 | | // |
768 | | // Strip trailing zeros from the password. |
769 | 1.61k | MemoryRemoveTrailingZeros(&s_inputAuthValues[sessionIndex]); |
770 | | |
771 | | // Get the authValue with trailing zeros removed |
772 | 1.61k | EntityGetAuthValue(associatedHandle, &authValue); |
773 | | |
774 | | // Success if the values are identical. |
775 | 1.61k | if(MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &authValue.b)) |
776 | 1.60k | { |
777 | 1.60k | return TPM_RC_SUCCESS; |
778 | 1.60k | } |
779 | 9 | else // if the digests are not identical |
780 | 9 | { |
781 | | // Invoke DA protection if applicable. |
782 | 9 | return IncrementLockout(sessionIndex); |
783 | 9 | } |
784 | 1.61k | } |
785 | | |
786 | | //*** ComputeCommandHMAC() |
787 | | // This function computes the HMAC for an authorization session in a command. |
788 | | /*(See part 1 specification -- this tag keeps this comment from showing up in |
789 | | // merged document which is probably good because this comment doesn't look right. |
790 | | // The sessionAuth value |
791 | | // authHMAC := HMACsHash((sessionKey | authValue), |
792 | | // (pHash | nonceNewer | nonceOlder | nonceTPMencrypt-only |
793 | | // | nonceTPMaudit | sessionAttributes)) |
794 | | // Where: |
795 | | // HMACsHash() The HMAC algorithm using the hash algorithm specified |
796 | | // when the session was started. |
797 | | // |
798 | | // sessionKey A value that is computed in a protocol-dependent way, |
799 | | // using KDFa. When used in an HMAC or KDF, the size field |
800 | | // for this value is not included. |
801 | | // |
802 | | // authValue A value that is found in the sensitive area of an entity. |
803 | | // When used in an HMAC or KDF, the size field for this |
804 | | // value is not included. |
805 | | // |
806 | | // pHash Hash of the command (cpHash) using the session hash. |
807 | | // When using a pHash in an HMAC computation, only the |
808 | | // digest is used. |
809 | | // |
810 | | // nonceNewer A value that is generated by the entity using the |
811 | | // session. A new nonce is generated on each use of the |
812 | | // session. For a command, this will be nonceCaller. |
813 | | // When used in an HMAC or KDF, the size field is not used. |
814 | | // |
815 | | // nonceOlder A TPM2B_NONCE that was received the previous time the |
816 | | // session was used. For a command, this is nonceTPM. |
817 | | // When used in an HMAC or KDF, the size field is not used. |
818 | | // |
819 | | // nonceTPMdecrypt The nonceTPM of the decrypt session is included in |
820 | | // the HMAC, but only in the command. |
821 | | // |
822 | | // nonceTPMencrypt The nonceTPM of the encrypt session is included in |
823 | | // the HMAC but only in the command. |
824 | | // |
825 | | // sessionAttributes A byte indicating the attributes associated with the |
826 | | // particular use of the session. |
827 | | */ |
828 | | static TPM2B_DIGEST* ComputeCommandHMAC( |
829 | | COMMAND* command, // IN: primary control structure |
830 | | UINT32 sessionIndex, // IN: index of session to be processed |
831 | | TPM2B_DIGEST* hmac // OUT: authorization HMAC |
832 | | ) |
833 | 0 | { |
834 | 0 | TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2)); |
835 | 0 | TPM2B_KEY key; |
836 | 0 | BYTE marshalBuffer[sizeof(TPMA_SESSION)]; |
837 | 0 | BYTE* buffer; |
838 | 0 | UINT32 marshalSize; |
839 | 0 | HMAC_STATE hmacState; |
840 | 0 | TPM2B_NONCE* nonceDecrypt; |
841 | 0 | TPM2B_NONCE* nonceEncrypt; |
842 | 0 | SESSION* session; |
843 | | // |
844 | 0 | nonceDecrypt = NULL; |
845 | 0 | nonceEncrypt = NULL; |
846 | | |
847 | | // Determine if extra nonceTPM values are going to be required. |
848 | | // If this is the first session (sessionIndex = 0) and it is an authorization |
849 | | // session that uses an HMAC, then check if additional session nonces are to be |
850 | | // included. |
851 | 0 | if(sessionIndex == 0 && s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) |
852 | 0 | { |
853 | | // If there is a decrypt session and if this is not the decrypt session, |
854 | | // then an extra nonce may be needed. |
855 | 0 | if(s_decryptSessionIndex != UNDEFINED_INDEX |
856 | 0 | && s_decryptSessionIndex != sessionIndex) |
857 | 0 | { |
858 | | // Will add the nonce for the decrypt session. |
859 | 0 | SESSION* decryptSession = |
860 | 0 | SessionGet(s_sessionHandles[s_decryptSessionIndex]); |
861 | 0 | nonceDecrypt = &decryptSession->nonceTPM; |
862 | 0 | } |
863 | | // Now repeat for the encrypt session. |
864 | 0 | if(s_encryptSessionIndex != UNDEFINED_INDEX |
865 | 0 | && s_encryptSessionIndex != sessionIndex |
866 | 0 | && s_encryptSessionIndex != s_decryptSessionIndex) |
867 | 0 | { |
868 | | // Have to have the nonce for the encrypt session. |
869 | 0 | SESSION* encryptSession = |
870 | 0 | SessionGet(s_sessionHandles[s_encryptSessionIndex]); |
871 | 0 | nonceEncrypt = &encryptSession->nonceTPM; |
872 | 0 | } |
873 | 0 | } |
874 | | |
875 | | // Continue with the HMAC processing. |
876 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
877 | | |
878 | | // Generate HMAC key. |
879 | 0 | MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer)); |
880 | | |
881 | | // Check if the session has an associated handle and if the associated entity |
882 | | // is the one to which the session is bound. If not, add the authValue of |
883 | | // this entity to the HMAC key. |
884 | | // If the session is bound to the object or the session is a policy session |
885 | | // with no authValue required, do not include the authValue in the HMAC key. |
886 | | // Note: For a policy session, its isBound attribute is CLEARED. |
887 | | // |
888 | | // Include the entity authValue if it is needed |
889 | 0 | if(session->attributes.includeAuth == SET) |
890 | 0 | { |
891 | 0 | TPM2B_AUTH authValue; |
892 | | // Get the entity authValue with trailing zeros removed |
893 | 0 | EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue); |
894 | | // add the authValue to the HMAC key |
895 | 0 | MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer)); |
896 | 0 | } |
897 | | // if the HMAC key size is 0, a NULL string HMAC is allowed |
898 | 0 | if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0) |
899 | 0 | { |
900 | 0 | hmac->t.size = 0; |
901 | 0 | return hmac; |
902 | 0 | } |
903 | | // Start HMAC |
904 | 0 | hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b); |
905 | | |
906 | | // Add cpHash |
907 | 0 | CryptDigestUpdate2B(&hmacState.hashState, |
908 | 0 | &ComputeCpHash(command, session->authHashAlg)->b); |
909 | | // Add nonces as required |
910 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b); |
911 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b); |
912 | 0 | if(nonceDecrypt != NULL) |
913 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &nonceDecrypt->b); |
914 | 0 | if(nonceEncrypt != NULL) |
915 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &nonceEncrypt->b); |
916 | | // Add sessionAttributes |
917 | 0 | buffer = marshalBuffer; |
918 | 0 | marshalSize = TPMA_SESSION_Marshal(&(s_attributes[sessionIndex]), &buffer, NULL); |
919 | 0 | CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer); |
920 | | // Complete the HMAC computation |
921 | 0 | CryptHmacEnd2B(&hmacState, &hmac->b); |
922 | |
|
923 | 0 | return hmac; |
924 | 0 | } |
925 | | |
926 | | //*** CheckSessionHMAC() |
927 | | // This function checks the HMAC of in a session. It uses ComputeCommandHMAC() |
928 | | // to compute the expected HMAC value and then compares the result with the |
929 | | // HMAC in the authorization session. The authorization is successful if they |
930 | | // are the same. |
931 | | // |
932 | | // If the authorizations are not the same, IncrementLockout() is called. It will |
933 | | // return TPM_RC_AUTH_FAIL if the failure caused the failureCount to increment. |
934 | | // Otherwise, it will return TPM_RC_BAD_AUTH. |
935 | | // |
936 | | // Return Type: TPM_RC |
937 | | // TPM_RC_AUTH_FAIL authorization failure caused failureCount increment |
938 | | // TPM_RC_BAD_AUTH authorization failure did not cause failureCount |
939 | | // increment |
940 | | // |
941 | | static TPM_RC CheckSessionHMAC( |
942 | | COMMAND* command, // IN: primary control structure |
943 | | UINT32 sessionIndex // IN: index of session to be processed |
944 | | ) |
945 | 0 | { |
946 | 0 | TPM2B_DIGEST hmac; // authHMAC for comparing |
947 | | // |
948 | | // Compute authHMAC |
949 | 0 | ComputeCommandHMAC(command, sessionIndex, &hmac); |
950 | | |
951 | | // Compare the input HMAC with the authHMAC computed above. |
952 | 0 | if(!MemoryEqual2B(&s_inputAuthValues[sessionIndex].b, &hmac.b)) |
953 | 0 | { |
954 | | // If an HMAC session has a failure, invoke the anti-hammering |
955 | | // if it applies to the authorized entity or the session. |
956 | | // Otherwise, just indicate that the authorization is bad. |
957 | 0 | return IncrementLockout(sessionIndex); |
958 | 0 | } |
959 | 0 | return TPM_RC_SUCCESS; |
960 | 0 | } |
961 | | |
962 | | //*** CheckPolicyAuthSession() |
963 | | // This function is used to validate the authorization in a policy session. |
964 | | // This function performs the following comparisons to see if a policy |
965 | | // authorization is properly provided. The check are: |
966 | | // a) compare policyDigest in session with authPolicy associated with |
967 | | // the entity to be authorized; |
968 | | // b) compare timeout if applicable; |
969 | | // c) compare commandCode if applicable; |
970 | | // d) compare cpHash if applicable; and |
971 | | // e) see if PCR values have changed since computed. |
972 | | // |
973 | | // If all the above checks succeed, the handle is authorized. |
974 | | // The order of these comparisons is not important because any failure will |
975 | | // result in the same error code. |
976 | | // |
977 | | // Return Type: TPM_RC |
978 | | // TPM_RC_PCR_CHANGED PCR value is not current |
979 | | // TPM_RC_POLICY_FAIL policy session fails |
980 | | // TPM_RC_LOCALITY command locality is not allowed |
981 | | // TPM_RC_POLICY_CC CC doesn't match |
982 | | // TPM_RC_EXPIRED policy session has expired |
983 | | // TPM_RC_PP PP is required but not asserted |
984 | | // TPM_RC_NV_UNAVAILABLE NV is not available for write |
985 | | // TPM_RC_NV_RATE NV is rate limiting |
986 | | static TPM_RC CheckPolicyAuthSession( |
987 | | COMMAND* command, // IN: primary parsing structure |
988 | | UINT32 sessionIndex // IN: index of session to be processed |
989 | | ) |
990 | 0 | { |
991 | 0 | SESSION* session; |
992 | 0 | TPM2B_DIGEST authPolicy; |
993 | 0 | TPMI_ALG_HASH policyAlg; |
994 | 0 | UINT8 locality; |
995 | | // |
996 | | // Initialize pointer to the authorization session. |
997 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
998 | | |
999 | | // If the command is TPM2_PolicySecret(), make sure that |
1000 | | // either password or authValue is required |
1001 | 0 | if(command->code == TPM_CC_PolicySecret |
1002 | 0 | && session->attributes.isPasswordNeeded == CLEAR |
1003 | 0 | && session->attributes.isAuthValueNeeded == CLEAR) |
1004 | 0 | return TPM_RC_MODE; |
1005 | | // See if the PCR counter for the session is still valid. |
1006 | 0 | if(!SessionPCRValueIsCurrent(session)) |
1007 | 0 | return TPM_RC_PCR_CHANGED; |
1008 | | // Get authPolicy. |
1009 | 0 | policyAlg = EntityGetAuthPolicy(s_associatedHandles[sessionIndex], &authPolicy); |
1010 | | // Compare authPolicy. |
1011 | 0 | if(!MemoryEqual2B(&session->u2.policyDigest.b, &authPolicy.b)) |
1012 | 0 | return TPM_RC_POLICY_FAIL; |
1013 | | // Policy is OK so check if the other factors are correct |
1014 | | |
1015 | | // Compare policy hash algorithm. |
1016 | 0 | if(policyAlg != session->authHashAlg) |
1017 | 0 | return TPM_RC_POLICY_FAIL; |
1018 | | |
1019 | | // Compare timeout. |
1020 | 0 | if(session->timeout != 0) |
1021 | 0 | { |
1022 | | // Cannot compare time if clock stop advancing. An TPM_RC_NV_UNAVAILABLE |
1023 | | // or TPM_RC_NV_RATE error may be returned here. This doesn't mean that |
1024 | | // a new nonce will be created just that, because TPM time can't advance |
1025 | | // we can't do time-based operations. |
1026 | 0 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
1027 | |
|
1028 | 0 | if((session->timeout < g_time) || (session->epoch != g_timeEpoch)) |
1029 | 0 | return TPM_RC_EXPIRED; |
1030 | 0 | } |
1031 | | // If command code is provided it must match |
1032 | 0 | if(session->commandCode != 0) |
1033 | 0 | { |
1034 | 0 | if(session->commandCode != command->code) |
1035 | 0 | return TPM_RC_POLICY_CC; |
1036 | 0 | } |
1037 | 0 | else |
1038 | 0 | { |
1039 | | // If command requires a DUP or ADMIN authorization, the session must have |
1040 | | // command code set. |
1041 | 0 | AUTH_ROLE role = CommandAuthRole(command->index, sessionIndex); |
1042 | 0 | if(role == AUTH_ADMIN || role == AUTH_DUP) |
1043 | 0 | return TPM_RC_POLICY_FAIL; |
1044 | 0 | } |
1045 | | // Check command locality. |
1046 | 0 | { |
1047 | 0 | BYTE sessionLocality[sizeof(TPMA_LOCALITY)]; |
1048 | 0 | BYTE* buffer = sessionLocality; |
1049 | | |
1050 | | // Get existing locality setting in canonical form |
1051 | 0 | sessionLocality[0] = 0; |
1052 | 0 | TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL); |
1053 | | |
1054 | | // See if the locality has been set |
1055 | 0 | if(sessionLocality[0] != 0) |
1056 | 0 | { |
1057 | | // If so, get the current locality |
1058 | 0 | locality = _plat__LocalityGet(); |
1059 | 0 | if(locality < 5) |
1060 | 0 | { |
1061 | 0 | if(((sessionLocality[0] & (1 << locality)) == 0) |
1062 | 0 | || sessionLocality[0] > 31) |
1063 | 0 | return TPM_RC_LOCALITY; |
1064 | 0 | } |
1065 | 0 | else if(locality > 31) |
1066 | 0 | { |
1067 | 0 | if(sessionLocality[0] != locality) |
1068 | 0 | return TPM_RC_LOCALITY; |
1069 | 0 | } |
1070 | 0 | else |
1071 | 0 | { |
1072 | | // Could throw an assert here but a locality error is just |
1073 | | // as good. It just means that, whatever the locality is, it isn't |
1074 | | // the locality requested so... |
1075 | 0 | return TPM_RC_LOCALITY; |
1076 | 0 | } |
1077 | 0 | } |
1078 | 0 | } // end of locality check |
1079 | | // Check physical presence. |
1080 | 0 | if(session->attributes.isPPRequired == SET && !_plat__PhysicalPresenceAsserted()) |
1081 | 0 | return TPM_RC_PP; |
1082 | | // Compare cpHash/nameHash/pHash/templateHash if defined. |
1083 | 0 | if(session->u1.cpHash.b.size != 0) |
1084 | 0 | { |
1085 | 0 | BOOL OK = FALSE; |
1086 | 0 | if(session->attributes.isCpHashDefined) |
1087 | | // Compare cpHash. |
1088 | 0 | OK = MemoryEqual2B(&session->u1.cpHash.b, |
1089 | 0 | &ComputeCpHash(command, session->authHashAlg)->b); |
1090 | 0 | else if(g_RuntimeProfile.stateFormatLevel >= 4 // libtpms added |
1091 | 0 | && session->attributes.isNameHashDefined) |
1092 | 0 | OK = CompareNameHash(command, session); |
1093 | 0 | else if(session->attributes.isParametersHashDefined) |
1094 | 0 | OK = CompareParametersHash(command, session); |
1095 | 0 | else if(session->attributes.isTemplateHashDefined) |
1096 | 0 | OK = CompareTemplateHash(command, session); |
1097 | 0 | else if (g_RuntimeProfile.stateFormatLevel < 4) // libtpms added: backwards compatibility |
1098 | 0 | OK = CompareNameHash(command, session); // libtpms added: backwards compatibility |
1099 | 0 | if(!OK) |
1100 | 0 | return TPM_RCS_POLICY_FAIL; |
1101 | 0 | } |
1102 | 0 | if(session->attributes.checkNvWritten) |
1103 | 0 | { |
1104 | 0 | NV_REF locator; |
1105 | 0 | NV_INDEX* nvIndex; |
1106 | | // |
1107 | | // If this is not an NV index, the policy makes no sense so fail it. |
1108 | 0 | if(HandleGetType(s_associatedHandles[sessionIndex]) != TPM_HT_NV_INDEX) |
1109 | 0 | return TPM_RC_POLICY_FAIL; |
1110 | | // Get the index data |
1111 | 0 | nvIndex = NvGetIndexInfo(s_associatedHandles[sessionIndex], &locator); |
1112 | | |
1113 | | // Make sure that the TPMA_WRITTEN_ATTRIBUTE has the desired state |
1114 | 0 | if((IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN)) |
1115 | 0 | != (session->attributes.nvWrittenState == SET)) |
1116 | 0 | return TPM_RC_POLICY_FAIL; |
1117 | 0 | } |
1118 | 0 | return TPM_RC_SUCCESS; |
1119 | 0 | } |
1120 | | |
1121 | | //*** RetrieveSessionData() |
1122 | | // This function will unmarshal the sessions in the session area of a command. The |
1123 | | // values are placed in the arrays that are defined at the beginning of this file. |
1124 | | // The normal unmarshaling errors are possible. |
1125 | | // |
1126 | | // Return Type: TPM_RC |
1127 | | // TPM_RC_SUCCSS unmarshaled without error |
1128 | | // TPM_RC_SIZE the number of bytes unmarshaled is not the same |
1129 | | // as the value for authorizationSize in the command |
1130 | | // |
1131 | | static TPM_RC RetrieveSessionData( |
1132 | | COMMAND* command // IN: main parsing structure for command |
1133 | | ) |
1134 | 1.78k | { |
1135 | 1.78k | int i; |
1136 | 1.78k | TPM_RC result; |
1137 | 1.78k | SESSION* session; |
1138 | 1.78k | TPMA_SESSION sessionAttributes; |
1139 | 1.78k | TPM_HT sessionType; |
1140 | 1.78k | INT32 sessionIndex; |
1141 | 1.78k | TPM_RC errorIndex; |
1142 | | // |
1143 | 1.78k | s_decryptSessionIndex = UNDEFINED_INDEX; |
1144 | 1.78k | s_encryptSessionIndex = UNDEFINED_INDEX; |
1145 | 1.78k | s_auditSessionIndex = UNDEFINED_INDEX; |
1146 | | |
1147 | 3.42k | for(sessionIndex = 0; command->authSize > 0; sessionIndex++) |
1148 | 1.80k | { |
1149 | 1.80k | errorIndex = TPM_RC_S + g_rcIndex[sessionIndex]; |
1150 | | |
1151 | | // If maximum allowed number of sessions has been parsed, return a size |
1152 | | // error with a session number that is larger than the number of allowed |
1153 | | // sessions |
1154 | 1.80k | if(sessionIndex == MAX_SESSION_NUM) |
1155 | 1 | return TPM_RCS_SIZE + errorIndex; |
1156 | | // make sure that the associated handle for each session starts out |
1157 | | // unassigned |
1158 | 1.80k | s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; |
1159 | | |
1160 | | // First parameter: Session handle. |
1161 | 1.80k | result = TPMI_SH_AUTH_SESSION_Unmarshal(&s_sessionHandles[sessionIndex], |
1162 | 1.80k | &command->parameterBuffer, |
1163 | 1.80k | &command->authSize, |
1164 | 1.80k | TRUE); |
1165 | 1.80k | if(result != TPM_RC_SUCCESS) |
1166 | 110 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
1167 | | // Second parameter: Nonce. |
1168 | 1.69k | result = TPM2B_NONCE_Unmarshal(&s_nonceCaller[sessionIndex], |
1169 | 1.69k | &command->parameterBuffer, |
1170 | 1.69k | &command->authSize); |
1171 | 1.69k | if(result != TPM_RC_SUCCESS) |
1172 | 21 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
1173 | | // Third parameter: sessionAttributes. |
1174 | 1.67k | result = TPMA_SESSION_Unmarshal(&s_attributes[sessionIndex], |
1175 | 1.67k | &command->parameterBuffer, |
1176 | 1.67k | &command->authSize); |
1177 | 1.67k | if(result != TPM_RC_SUCCESS) |
1178 | 4 | return result + TPM_RC_S + g_rcIndex[sessionIndex]; |
1179 | | // Fourth parameter: authValue (PW or HMAC). |
1180 | 1.67k | result = TPM2B_AUTH_Unmarshal(&s_inputAuthValues[sessionIndex], |
1181 | 1.67k | &command->parameterBuffer, |
1182 | 1.67k | &command->authSize); |
1183 | 1.67k | if(result != TPM_RC_SUCCESS) |
1184 | 21 | return result + errorIndex; |
1185 | | |
1186 | 1.65k | sessionAttributes = s_attributes[sessionIndex]; |
1187 | 1.65k | if(s_sessionHandles[sessionIndex] == TPM_RS_PW) |
1188 | 1.64k | { |
1189 | | // A PWAP session needs additional processing. |
1190 | | // Can't have any attributes set other than continueSession bit |
1191 | 1.64k | if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt) |
1192 | 1.64k | || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt) |
1193 | 1.64k | || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit) |
1194 | 1.64k | || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive) |
1195 | 1.64k | || IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset)) |
1196 | 5 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1197 | | // The nonce size must be zero. |
1198 | 1.64k | if(s_nonceCaller[sessionIndex].t.size != 0) |
1199 | 3 | return TPM_RCS_NONCE + errorIndex; |
1200 | 1.63k | continue; |
1201 | 1.64k | } |
1202 | | // For not password sessions... |
1203 | | // Find out if the session is loaded. |
1204 | 6 | if(!SessionIsLoaded(s_sessionHandles[sessionIndex])) |
1205 | 6 | return TPM_RC_REFERENCE_S0 + sessionIndex; |
1206 | 0 | sessionType = HandleGetType(s_sessionHandles[sessionIndex]); |
1207 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
1208 | | |
1209 | | // Check if the session is an HMAC/policy session. |
1210 | 0 | if((session->attributes.isPolicy == SET && sessionType == TPM_HT_HMAC_SESSION) |
1211 | 0 | || (session->attributes.isPolicy == CLEAR |
1212 | 0 | && sessionType == TPM_HT_POLICY_SESSION)) |
1213 | 0 | return TPM_RCS_HANDLE + errorIndex; |
1214 | | // Check that this handle has not previously been used. |
1215 | 0 | for(i = 0; i < sessionIndex; i++) |
1216 | 0 | { |
1217 | 0 | if(s_sessionHandles[i] == s_sessionHandles[sessionIndex]) |
1218 | 0 | return TPM_RCS_HANDLE + errorIndex; |
1219 | 0 | } |
1220 | | // If the session is used for parameter encryption or audit as well, set |
1221 | | // the corresponding Indexes. |
1222 | | |
1223 | | // First process decrypt. |
1224 | 0 | if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, decrypt)) |
1225 | 0 | { |
1226 | | // Check if the commandCode allows command parameter encryption. |
1227 | 0 | if(DecryptSize(command->index) == 0) |
1228 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1229 | | // Encrypt attribute can only appear in one session |
1230 | 0 | if(s_decryptSessionIndex != UNDEFINED_INDEX) |
1231 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1232 | | // Can't decrypt if the session's symmetric algorithm is TPM_ALG_NULL |
1233 | 0 | if(session->symmetric.algorithm == TPM_ALG_NULL) |
1234 | 0 | return TPM_RCS_SYMMETRIC + errorIndex; |
1235 | | // All checks passed, so set the index for the session used to decrypt |
1236 | | // a command parameter. |
1237 | 0 | s_decryptSessionIndex = sessionIndex; |
1238 | 0 | } |
1239 | | // Now process encrypt. |
1240 | 0 | if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, encrypt)) |
1241 | 0 | { |
1242 | | // Check if the commandCode allows response parameter encryption. |
1243 | 0 | if(EncryptSize(command->index) == 0) |
1244 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1245 | | // Encrypt attribute can only appear in one session. |
1246 | 0 | if(s_encryptSessionIndex != UNDEFINED_INDEX) |
1247 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1248 | | // Can't encrypt if the session's symmetric algorithm is TPM_ALG_NULL |
1249 | 0 | if(session->symmetric.algorithm == TPM_ALG_NULL) |
1250 | 0 | return TPM_RCS_SYMMETRIC + errorIndex; |
1251 | | // All checks passed, so set the index for the session used to encrypt |
1252 | | // a response parameter. |
1253 | 0 | s_encryptSessionIndex = sessionIndex; |
1254 | 0 | } |
1255 | | // At last process audit. |
1256 | 0 | if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, audit)) |
1257 | 0 | { |
1258 | | // Audit attribute can only appear in one session. |
1259 | 0 | if(s_auditSessionIndex != UNDEFINED_INDEX) |
1260 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1261 | | // An audit session can not be policy session. |
1262 | 0 | if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION) |
1263 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1264 | | // If this is a reset of the audit session, or the first use |
1265 | | // of the session as an audit session, it doesn't matter what |
1266 | | // the exclusive state is. The session will become exclusive. |
1267 | 0 | if(!IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditReset) |
1268 | 0 | && session->attributes.isAudit == SET) |
1269 | 0 | { |
1270 | | // Not first use or reset. If auditExlusive is SET, then this |
1271 | | // session must be the current exclusive session. |
1272 | 0 | if(IS_ATTRIBUTE(sessionAttributes, TPMA_SESSION, auditExclusive) |
1273 | 0 | && g_exclusiveAuditSession != s_sessionHandles[sessionIndex]) |
1274 | 0 | return TPM_RC_EXCLUSIVE; |
1275 | 0 | } |
1276 | 0 | s_auditSessionIndex = sessionIndex; |
1277 | 0 | } |
1278 | | // Initialize associated handle as undefined. This will be changed when |
1279 | | // the handles are processed. |
1280 | 0 | s_associatedHandles[sessionIndex] = TPM_RH_UNASSIGNED; |
1281 | 0 | } |
1282 | 1.61k | command->sessionNum = sessionIndex; |
1283 | 1.61k | return TPM_RC_SUCCESS; |
1284 | 1.78k | } |
1285 | | |
1286 | | //*** CheckLockedOut() |
1287 | | // This function checks to see if the TPM is in lockout. This function should only |
1288 | | // be called if the entity being checked is subject to DA protection. The TPM |
1289 | | // is in lockout if the NV is not available and a DA write is pending. Otherwise |
1290 | | // the TPM is locked out if checking for lockoutAuth ('lockoutAuthCheck' == TRUE) |
1291 | | // and use of lockoutAuth is disabled, or 'failedTries' >= 'maxTries' |
1292 | | // Return Type: TPM_RC |
1293 | | // TPM_RC_NV_RATE NV is rate limiting |
1294 | | // TPM_RC_NV_UNAVAILABLE NV is not available at this time |
1295 | | // TPM_RC_LOCKOUT TPM is in lockout |
1296 | | static TPM_RC CheckLockedOut( |
1297 | | BOOL lockoutAuthCheck // IN: TRUE if checking is for lockoutAuth |
1298 | | ) |
1299 | 13 | { |
1300 | | // If NV is unavailable, and current cycle state recorded in NV is not |
1301 | | // SU_NONE_VALUE, refuse to check any authorization because we would |
1302 | | // not be able to handle a DA failure. |
1303 | 13 | if(!NV_IS_AVAILABLE && NV_IS_ORDERLY) |
1304 | 0 | return g_NvStatus; |
1305 | | // Check if DA info needs to be updated in NV. |
1306 | 13 | if(s_DAPendingOnNV) |
1307 | 0 | { |
1308 | | // If NV is accessible, |
1309 | 0 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
1310 | | |
1311 | | // ... write the pending DA data and proceed. |
1312 | 0 | NV_SYNC_PERSISTENT(lockOutAuthEnabled); |
1313 | 0 | NV_SYNC_PERSISTENT(failedTries); |
1314 | 0 | s_DAPendingOnNV = FALSE; |
1315 | 0 | } |
1316 | | // Lockout is in effect if checking for lockoutAuth and use of lockoutAuth |
1317 | | // is disabled... |
1318 | 13 | if(lockoutAuthCheck) |
1319 | 13 | { |
1320 | 13 | if(gp.lockOutAuthEnabled == FALSE) |
1321 | 0 | return TPM_RC_LOCKOUT; |
1322 | 13 | } |
1323 | 0 | else |
1324 | 0 | { |
1325 | | // ... or if the number of failed tries has been maxed out. |
1326 | 0 | if(gp.failedTries >= gp.maxTries) |
1327 | 0 | return TPM_RC_LOCKOUT; |
1328 | 0 | #if USE_DA_USED |
1329 | | // If the daUsed flag is not SET, then no DA validation until the |
1330 | | // daUsed state is written to NV |
1331 | 0 | if(!g_daUsed) |
1332 | 0 | { |
1333 | 0 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
1334 | 0 | g_daUsed = TRUE; |
1335 | 0 | gp.orderlyState = SU_DA_USED_VALUE; |
1336 | 0 | NV_SYNC_PERSISTENT(orderlyState); |
1337 | 0 | return TPM_RC_RETRY; |
1338 | 0 | } |
1339 | 0 | #endif |
1340 | 0 | } |
1341 | 13 | return TPM_RC_SUCCESS; |
1342 | 13 | } |
1343 | | |
1344 | | //*** CheckAuthSession() |
1345 | | // This function checks that the authorization session properly authorizes the |
1346 | | // use of the associated handle. |
1347 | | // |
1348 | | // Return Type: TPM_RC |
1349 | | // TPM_RC_LOCKOUT entity is protected by DA and TPM is in |
1350 | | // lockout, or TPM is locked out on NV update |
1351 | | // pending on DA parameters |
1352 | | // |
1353 | | // TPM_RC_PP Physical Presence is required but not provided |
1354 | | // TPM_RC_AUTH_FAIL HMAC or PW authorization failed |
1355 | | // with DA side-effects (can be a policy session) |
1356 | | // |
1357 | | // TPM_RC_BAD_AUTH HMAC or PW authorization failed without DA |
1358 | | // side-effects (can be a policy session) |
1359 | | // |
1360 | | // TPM_RC_POLICY_FAIL if policy session fails |
1361 | | // TPM_RC_POLICY_CC command code of policy was wrong |
1362 | | // TPM_RC_EXPIRED the policy session has expired |
1363 | | // TPM_RC_PCR |
1364 | | // TPM_RC_AUTH_UNAVAILABLE authValue or authPolicy unavailable |
1365 | | static TPM_RC CheckAuthSession( |
1366 | | COMMAND* command, // IN: primary parsing structure |
1367 | | UINT32 sessionIndex // IN: index of session to be processed |
1368 | | ) |
1369 | 1.61k | { |
1370 | 1.61k | TPM_RC result = TPM_RC_SUCCESS; |
1371 | 1.61k | SESSION* session = NULL; |
1372 | 1.61k | TPM_HANDLE sessionHandle = s_sessionHandles[sessionIndex]; |
1373 | 1.61k | TPM_HANDLE associatedHandle = s_associatedHandles[sessionIndex]; |
1374 | 1.61k | TPM_HT sessionHandleType = HandleGetType(sessionHandle); |
1375 | 1.61k | BOOL authUsed; |
1376 | | // |
1377 | 1.61k | pAssert(sessionHandle != TPM_RH_UNASSIGNED); |
1378 | | |
1379 | | // Take care of physical presence |
1380 | 1.61k | if(associatedHandle == TPM_RH_PLATFORM) |
1381 | 349 | { |
1382 | | // If the physical presence is required for this command, check for PP |
1383 | | // assertion. If it isn't asserted, no point going any further. |
1384 | 349 | if(PhysicalPresenceIsRequired(command->index) |
1385 | 349 | && !_plat__PhysicalPresenceAsserted()) |
1386 | 1 | return TPM_RC_PP; |
1387 | 349 | } |
1388 | 1.61k | if(sessionHandle != TPM_RS_PW) |
1389 | 0 | { |
1390 | 0 | session = SessionGet(sessionHandle); |
1391 | | |
1392 | | // Set includeAuth to indicate if DA checking will be required and if the |
1393 | | // authValue will be included in any HMAC. |
1394 | 0 | if(sessionHandleType == TPM_HT_POLICY_SESSION) |
1395 | 0 | { |
1396 | | // For a policy session, will check the DA status of the entity if either |
1397 | | // isAuthValueNeeded or isPasswordNeeded is SET. |
1398 | 0 | session->attributes.includeAuth = session->attributes.isAuthValueNeeded |
1399 | 0 | || session->attributes.isPasswordNeeded; |
1400 | 0 | } |
1401 | 0 | else |
1402 | 0 | { |
1403 | | // For an HMAC session, need to check unless the session |
1404 | | // is bound. |
1405 | 0 | session->attributes.includeAuth = |
1406 | 0 | !IsSessionBindEntity(s_associatedHandles[sessionIndex], session); |
1407 | 0 | } |
1408 | 0 | authUsed = session->attributes.includeAuth; |
1409 | 0 | } |
1410 | 1.61k | else |
1411 | | // Password session |
1412 | 1.61k | authUsed = TRUE; |
1413 | | // If the authorization session is going to use an authValue, then make sure |
1414 | | // that access to that authValue isn't locked out. |
1415 | 1.61k | if(authUsed) |
1416 | 1.61k | { |
1417 | | // See if entity is subject to lockout. |
1418 | 1.61k | if(!IsDAExempted(associatedHandle)) |
1419 | 13 | { |
1420 | | // See if in lockout |
1421 | 13 | result = CheckLockedOut(associatedHandle == TPM_RH_LOCKOUT); |
1422 | 13 | if(result != TPM_RC_SUCCESS) |
1423 | 0 | return result; |
1424 | 13 | } |
1425 | 1.61k | } |
1426 | | // Policy or HMAC+PW? |
1427 | 1.61k | if(sessionHandleType != TPM_HT_POLICY_SESSION) |
1428 | 1.61k | { |
1429 | | // for non-policy session make sure that a policy session is not required |
1430 | 1.61k | if(IsPolicySessionRequired(command->index, sessionIndex)) |
1431 | 0 | return TPM_RC_AUTH_TYPE; |
1432 | | // The authValue must be available. |
1433 | | // Note: The authValue is going to be "used" even if it is an EmptyAuth. |
1434 | | // and the session is bound. |
1435 | 1.61k | if(!IsAuthValueAvailable(associatedHandle, command->index, sessionIndex)) |
1436 | 0 | return TPM_RC_AUTH_UNAVAILABLE; |
1437 | 1.61k | } |
1438 | 0 | else |
1439 | 0 | { |
1440 | | // ... see if the entity has a policy, ... |
1441 | | // Note: IsAuthPolicyAvalable will return FALSE if the sensitive area of the |
1442 | | // object is not loaded |
1443 | 0 | if(!IsAuthPolicyAvailable(associatedHandle, command->index, sessionIndex)) |
1444 | 0 | return TPM_RC_AUTH_UNAVAILABLE; |
1445 | | // ... and check the policy session. |
1446 | 0 | result = CheckPolicyAuthSession(command, sessionIndex); |
1447 | 0 | if(result != TPM_RC_SUCCESS) |
1448 | 0 | return result; |
1449 | 0 | } |
1450 | | // Check authorization according to the type |
1451 | 1.61k | if((TPM_RS_PW == sessionHandle) || (session->attributes.isPasswordNeeded == SET)) |
1452 | 1.61k | result = CheckPWAuthSession(sessionIndex); |
1453 | 0 | else |
1454 | 0 | result = CheckSessionHMAC(command, sessionIndex); |
1455 | | // Do processing for PIN Indexes are only three possibilities for 'result' at |
1456 | | // this point: TPM_RC_SUCCESS, TPM_RC_AUTH_FAIL, and TPM_RC_BAD_AUTH. |
1457 | | // For all these cases, we would have to process a PIN index if the |
1458 | | // authValue of the index was used for authorization. |
1459 | 1.61k | if((TPM_HT_NV_INDEX == HandleGetType(associatedHandle)) && authUsed) |
1460 | 0 | { |
1461 | 0 | NV_REF locator; |
1462 | 0 | NV_INDEX* nvIndex = NvGetIndexInfo(associatedHandle, &locator); |
1463 | 0 | NV_PIN pinData; |
1464 | 0 | TPMA_NV nvAttributes; |
1465 | | // |
1466 | 0 | pAssert(nvIndex != NULL); |
1467 | 0 | nvAttributes = nvIndex->publicArea.attributes; |
1468 | | // If this is a PIN FAIL index and the value has been written |
1469 | | // then we can update the counter (increment or clear) |
1470 | 0 | if(IsNvPinFailIndex(nvAttributes) |
1471 | 0 | && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN)) |
1472 | 0 | { |
1473 | 0 | pinData.intVal = NvGetUINT64Data(nvIndex, locator); |
1474 | 0 | if(result != TPM_RC_SUCCESS) |
1475 | 0 | pinData.pin.pinCount++; |
1476 | 0 | else |
1477 | 0 | pinData.pin.pinCount = 0; |
1478 | 0 | NvWriteUINT64Data(nvIndex, pinData.intVal); |
1479 | 0 | } |
1480 | | // If this is a PIN PASS Index, increment if we have used the |
1481 | | // authorization value. |
1482 | | // NOTE: If the counter has already hit the limit, then we |
1483 | | // would not get here because the authorization value would not |
1484 | | // be available and the TPM would have returned before it gets here |
1485 | 0 | else if(IsNvPinPassIndex(nvAttributes) |
1486 | 0 | && IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN) |
1487 | 0 | && result == TPM_RC_SUCCESS) |
1488 | 0 | { |
1489 | | // If the access is valid, then increment the use counter |
1490 | 0 | pinData.intVal = NvGetUINT64Data(nvIndex, locator); |
1491 | 0 | pinData.pin.pinCount++; |
1492 | 0 | NvWriteUINT64Data(nvIndex, pinData.intVal); |
1493 | 0 | } |
1494 | 0 | } |
1495 | 1.61k | return result; |
1496 | 1.61k | } |
1497 | | |
1498 | | #if CC_GetCommandAuditDigest |
1499 | | //*** CheckCommandAudit() |
1500 | | // This function is called before the command is processed if audit is enabled |
1501 | | // for the command. It will check to see if the audit can be performed and |
1502 | | // will ensure that the cpHash is available for the audit. |
1503 | | // Return Type: TPM_RC |
1504 | | // TPM_RC_NV_UNAVAILABLE NV is not available for write |
1505 | | // TPM_RC_NV_RATE NV is rate limiting |
1506 | | static TPM_RC CheckCommandAudit(COMMAND* command) |
1507 | 183 | { |
1508 | | // If the audit digest is clear and command audit is required, NV must be |
1509 | | // available so that TPM2_GetCommandAuditDigest() is able to increment |
1510 | | // audit counter. If NV is not available, the function bails out to prevent |
1511 | | // the TPM from attempting an operation that would fail anyway. |
1512 | 183 | if(gr.commandAuditDigest.t.size == 0 |
1513 | 183 | || GetCommandCode(command->index) == TPM_CC_GetCommandAuditDigest) |
1514 | 183 | { |
1515 | 183 | RETURN_IF_NV_IS_NOT_AVAILABLE; |
1516 | 183 | } |
1517 | | // Make sure that the cpHash is computed for the algorithm |
1518 | 183 | ComputeCpHash(command, gp.auditHashAlg); |
1519 | 183 | return TPM_RC_SUCCESS; |
1520 | 183 | } |
1521 | | #endif |
1522 | | |
1523 | | //*** ParseSessionBuffer() |
1524 | | // This function is the entry function for command session processing. |
1525 | | // It iterates sessions in session area and reports if the required authorization |
1526 | | // has been properly provided. It also processes audit session and passes the |
1527 | | // information of encryption sessions to parameter encryption module. |
1528 | | // |
1529 | | // Return Type: TPM_RC |
1530 | | // various parsing failure or authorization failure |
1531 | | // |
1532 | | TPM_RC |
1533 | | ParseSessionBuffer(COMMAND* command // IN: the structure that contains |
1534 | | ) |
1535 | 1.78k | { |
1536 | 1.78k | TPM_RC result; |
1537 | 1.78k | UINT32 i; |
1538 | 1.78k | INT32 size = 0; |
1539 | 1.78k | TPM2B_AUTH extraKey; |
1540 | 1.78k | UINT32 sessionIndex; |
1541 | 1.78k | TPM_RC errorIndex; |
1542 | 1.78k | SESSION* session = NULL; |
1543 | | // |
1544 | | // Check if a command allows any session in its session area. |
1545 | 1.78k | if(!IsSessionAllowed(command->index)) |
1546 | 2 | return TPM_RC_AUTH_CONTEXT; |
1547 | | // Default-initialization. |
1548 | 1.78k | command->sessionNum = 0; |
1549 | | |
1550 | 1.78k | result = RetrieveSessionData(command); |
1551 | 1.78k | if(result != TPM_RC_SUCCESS) |
1552 | 171 | return result; |
1553 | | // There is no command in the TPM spec that has more handles than |
1554 | | // MAX_SESSION_NUM. |
1555 | 1.61k | pAssert(command->handleNum <= MAX_SESSION_NUM); |
1556 | | |
1557 | | // Associate the session with an authorization handle. |
1558 | 3.25k | for(i = 0; i < command->handleNum; i++) |
1559 | 1.63k | { |
1560 | 1.63k | if(CommandAuthRole(command->index, i) != AUTH_NONE) |
1561 | 1.61k | { |
1562 | | // If the received session number is less than the number of handles |
1563 | | // that requires authorization, an error should be returned. |
1564 | | // Note: for all the TPM 2.0 commands, handles requiring |
1565 | | // authorization come first in a command input and there are only ever |
1566 | | // two values requiring authorization |
1567 | 1.61k | if(command->sessionNum == 0) // libtpms added begin (Coverity 1550499) |
1568 | 0 | return TPM_RC_AUTH_MISSING; // libtpms added end |
1569 | 1.61k | if(i > (command->sessionNum - 1)) |
1570 | 1 | return TPM_RC_AUTH_MISSING; |
1571 | | // Record the handle associated with the authorization session |
1572 | 1.61k | s_associatedHandles[i] = HierarchyNormalizeHandle(command->handles[i]); |
1573 | 1.61k | } |
1574 | 1.63k | } |
1575 | | // Consistency checks are done first to avoid authorization failure when the |
1576 | | // command will not be executed anyway. |
1577 | 3.21k | for(sessionIndex = 0; sessionIndex < command->sessionNum; sessionIndex++) |
1578 | 1.61k | { |
1579 | 1.61k | errorIndex = TPM_RC_S + g_rcIndex[sessionIndex]; |
1580 | | // PW session must be an authorization session |
1581 | 1.61k | if(s_sessionHandles[sessionIndex] == TPM_RS_PW) |
1582 | 1.61k | { |
1583 | 1.61k | if(s_associatedHandles[sessionIndex] == TPM_RH_UNASSIGNED) |
1584 | 3 | return TPM_RCS_HANDLE + errorIndex; |
1585 | | // a password session can't be audit, encrypt or decrypt |
1586 | 1.61k | if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit) |
1587 | 1.61k | || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt) |
1588 | 1.61k | || IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt)) |
1589 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1590 | 1.61k | session = NULL; |
1591 | 1.61k | } |
1592 | 0 | else |
1593 | 0 | { |
1594 | 0 | session = SessionGet(s_sessionHandles[sessionIndex]); |
1595 | | |
1596 | | // A trial session can not appear in session area, because it cannot |
1597 | | // be used for authorization, audit or encrypt/decrypt. |
1598 | 0 | if(session->attributes.isTrialPolicy == SET) |
1599 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1600 | | |
1601 | | // See if the session is bound to a DA protected entity |
1602 | | // NOTE: Since a policy session is never bound, a policy is still |
1603 | | // usable even if the object is DA protected and the TPM is in |
1604 | | // lockout. |
1605 | 0 | if(session->attributes.isDaBound == SET) |
1606 | 0 | { |
1607 | 0 | result = CheckLockedOut(session->attributes.isLockoutBound == SET); |
1608 | 0 | if(result != TPM_RC_SUCCESS) |
1609 | 0 | return result; |
1610 | 0 | } |
1611 | | // If this session is for auditing, make sure the cpHash is computed. |
1612 | 0 | if(IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit)) |
1613 | 0 | ComputeCpHash(command, session->authHashAlg); |
1614 | 0 | } |
1615 | | |
1616 | | // if the session has an associated handle, check the authorization |
1617 | 1.61k | if(s_associatedHandles[sessionIndex] != TPM_RH_UNASSIGNED) |
1618 | 1.61k | { |
1619 | 1.61k | result = CheckAuthSession(command, sessionIndex); |
1620 | 1.61k | if(result != TPM_RC_SUCCESS) |
1621 | 10 | return RcSafeAddToResult(result, errorIndex); |
1622 | 1.61k | } |
1623 | 0 | else |
1624 | 0 | { |
1625 | | // a session that is not for authorization must either be encrypt, |
1626 | | // decrypt, or audit |
1627 | 0 | if(!IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, audit) |
1628 | 0 | && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, encrypt) |
1629 | 0 | && !IS_ATTRIBUTE(s_attributes[sessionIndex], TPMA_SESSION, decrypt)) |
1630 | 0 | return TPM_RCS_ATTRIBUTES + errorIndex; |
1631 | | |
1632 | | // no authValue included in any of the HMAC computations |
1633 | 0 | pAssert(session != NULL); |
1634 | 0 | session->attributes.includeAuth = CLEAR; |
1635 | | |
1636 | | // check HMAC for encrypt/decrypt/audit only sessions |
1637 | 0 | result = CheckSessionHMAC(command, sessionIndex); |
1638 | 0 | if(result != TPM_RC_SUCCESS) |
1639 | 0 | return RcSafeAddToResult(result, errorIndex); |
1640 | 0 | } |
1641 | 1.61k | } |
1642 | 1.60k | #if CC_GetCommandAuditDigest |
1643 | | // Check if the command should be audited. Need to do this before any parameter |
1644 | | // encryption so that the cpHash for the audit is correct |
1645 | 1.60k | if(CommandAuditIsRequired(command->index)) |
1646 | 183 | { |
1647 | 183 | result = CheckCommandAudit(command); |
1648 | 183 | if(result != TPM_RC_SUCCESS) |
1649 | 0 | return result; // No session number to reference |
1650 | 183 | } |
1651 | 1.60k | #endif |
1652 | | // Decrypt the first parameter if applicable. This should be the last operation |
1653 | | // in session processing. |
1654 | | // If the encrypt session is associated with a handle and the handle's |
1655 | | // authValue is available, then authValue is concatenated with sessionKey to |
1656 | | // generate encryption key, no matter if the handle is the session bound entity |
1657 | | // or not. |
1658 | 1.60k | if(s_decryptSessionIndex != UNDEFINED_INDEX) |
1659 | 0 | { |
1660 | | // If this is an authorization session, include the authValue in the |
1661 | | // generation of the decryption key |
1662 | 0 | if(s_associatedHandles[s_decryptSessionIndex] != TPM_RH_UNASSIGNED) |
1663 | 0 | { |
1664 | 0 | EntityGetAuthValue(s_associatedHandles[s_decryptSessionIndex], &extraKey); |
1665 | 0 | } |
1666 | 0 | else |
1667 | 0 | { |
1668 | 0 | extraKey.b.size = 0; |
1669 | 0 | } |
1670 | 0 | size = DecryptSize(command->index); |
1671 | 0 | result = CryptParameterDecryption(s_sessionHandles[s_decryptSessionIndex], |
1672 | 0 | &s_nonceCaller[s_decryptSessionIndex].b, |
1673 | 0 | command->parameterSize, |
1674 | 0 | (UINT16)size, |
1675 | 0 | &extraKey, |
1676 | 0 | command->parameterBuffer); |
1677 | 0 | if(result != TPM_RC_SUCCESS) |
1678 | 0 | return RcSafeAddToResult(result, |
1679 | 0 | TPM_RC_S + g_rcIndex[s_decryptSessionIndex]); |
1680 | 0 | } |
1681 | | |
1682 | 1.60k | return TPM_RC_SUCCESS; |
1683 | 1.60k | } |
1684 | | |
1685 | | //*** CheckAuthNoSession() |
1686 | | // Function to process a command with no session associated. |
1687 | | // The function makes sure all the handles in the command require no authorization. |
1688 | | // |
1689 | | // Return Type: TPM_RC |
1690 | | // TPM_RC_AUTH_MISSING failure - one or more handles require |
1691 | | // authorization |
1692 | | TPM_RC |
1693 | | CheckAuthNoSession(COMMAND* command // IN: command parsing structure |
1694 | | ) |
1695 | 10.2k | { |
1696 | 10.2k | UINT32 i; |
1697 | 10.2k | #if CC_GetCommandAuditDigest |
1698 | 10.2k | TPM_RC result = TPM_RC_SUCCESS; |
1699 | 10.2k | #endif |
1700 | | // |
1701 | | // Check if the command requires authorization |
1702 | 10.4k | for(i = 0; i < command->handleNum; i++) |
1703 | 127 | { |
1704 | 127 | if(CommandAuthRole(command->index, i) != AUTH_NONE) |
1705 | 13 | return TPM_RC_AUTH_MISSING; |
1706 | 127 | } |
1707 | 10.2k | #if CC_GetCommandAuditDigest |
1708 | | // Check if the command should be audited. |
1709 | 10.2k | if(CommandAuditIsRequired(command->index)) |
1710 | 0 | { |
1711 | 0 | result = CheckCommandAudit(command); |
1712 | 0 | if(result != TPM_RC_SUCCESS) |
1713 | 0 | return result; |
1714 | 0 | } |
1715 | 10.2k | #endif |
1716 | | // Initialize number of sessions to be 0 |
1717 | 10.2k | command->sessionNum = 0; |
1718 | | |
1719 | 10.2k | return TPM_RC_SUCCESS; |
1720 | 10.2k | } |
1721 | | |
1722 | | //** Response Session Processing |
1723 | | //*** Introduction |
1724 | | // |
1725 | | // The following functions build the session area in a response and handle |
1726 | | // the audit sessions (if present). |
1727 | | // |
1728 | | |
1729 | | //*** ComputeRpHash() |
1730 | | // Function to compute rpHash (Response Parameter Hash). The rpHash is only |
1731 | | // computed if there is an HMAC authorization session and the return code is |
1732 | | // TPM_RC_SUCCESS. |
1733 | | static TPM2B_DIGEST* ComputeRpHash( |
1734 | | COMMAND* command, // IN: command structure |
1735 | | TPM_ALG_ID hashAlg // IN: hash algorithm to compute rpHash |
1736 | | ) |
1737 | 126 | { |
1738 | 126 | TPM2B_DIGEST* rpHash = GetRpHashPointer(command, hashAlg); |
1739 | 126 | HASH_STATE hashState; |
1740 | | // |
1741 | 126 | if(rpHash->t.size == 0) |
1742 | 126 | { |
1743 | | // rpHash := hash(responseCode || commandCode || parameters) |
1744 | | |
1745 | | // Initiate hash creation. |
1746 | 126 | rpHash->t.size = CryptHashStart(&hashState, hashAlg); |
1747 | | |
1748 | | // Add hash constituents. |
1749 | 126 | CryptDigestUpdateInt(&hashState, sizeof(TPM_RC), TPM_RC_SUCCESS); |
1750 | 126 | CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), command->code); |
1751 | 126 | CryptDigestUpdate( |
1752 | 126 | &hashState, command->parameterSize, command->parameterBuffer); |
1753 | | // Complete hash computation. |
1754 | 126 | CryptHashEnd2B(&hashState, &rpHash->b); |
1755 | 126 | } |
1756 | 126 | return rpHash; |
1757 | 126 | } |
1758 | | |
1759 | | //*** InitAuditSession() |
1760 | | // This function initializes the audit data in an audit session. |
1761 | | static void InitAuditSession(SESSION* session // session to be initialized |
1762 | | ) |
1763 | 0 | { |
1764 | | // Mark session as an audit session. |
1765 | 0 | session->attributes.isAudit = SET; |
1766 | | |
1767 | | // Audit session can not be bound. |
1768 | 0 | session->attributes.isBound = CLEAR; |
1769 | | |
1770 | | // Size of the audit log is the size of session hash algorithm digest. |
1771 | 0 | session->u2.auditDigest.t.size = CryptHashGetDigestSize(session->authHashAlg); |
1772 | | |
1773 | | // Set the original digest value to be 0. |
1774 | 0 | MemorySet(&session->u2.auditDigest.t.buffer, 0, session->u2.auditDigest.t.size); |
1775 | 0 | return; |
1776 | 0 | } |
1777 | | |
1778 | | //*** UpdateAuditDigest |
1779 | | // Function to update an audit digest |
1780 | | static void UpdateAuditDigest( |
1781 | | COMMAND* command, TPMI_ALG_HASH hashAlg, TPM2B_DIGEST* digest) |
1782 | 126 | { |
1783 | 126 | HASH_STATE hashState; |
1784 | 126 | TPM2B_DIGEST* cpHash = GetCpHash(command, hashAlg); |
1785 | 126 | TPM2B_DIGEST* rpHash = ComputeRpHash(command, hashAlg); |
1786 | | // |
1787 | 126 | pAssert(cpHash != NULL); |
1788 | | |
1789 | | // digestNew := hash (digestOld || cpHash || rpHash) |
1790 | | // Start hash computation. |
1791 | 126 | digest->t.size = CryptHashStart(&hashState, hashAlg); |
1792 | | // Add old digest. |
1793 | 126 | CryptDigestUpdate2B(&hashState, &digest->b); |
1794 | | // Add cpHash |
1795 | 126 | CryptDigestUpdate2B(&hashState, &cpHash->b); |
1796 | | // Add rpHash |
1797 | 126 | CryptDigestUpdate2B(&hashState, &rpHash->b); |
1798 | | // Finalize the hash. |
1799 | 126 | CryptHashEnd2B(&hashState, &digest->b); |
1800 | 126 | } |
1801 | | |
1802 | | //*** Audit() |
1803 | | //This function updates the audit digest in an audit session. |
1804 | | static void Audit(COMMAND* command, // IN: primary control structure |
1805 | | SESSION* auditSession // IN: loaded audit session |
1806 | | ) |
1807 | 0 | { |
1808 | 0 | UpdateAuditDigest( |
1809 | 0 | command, auditSession->authHashAlg, &auditSession->u2.auditDigest); |
1810 | 0 | return; |
1811 | 0 | } |
1812 | | |
1813 | | #if CC_GetCommandAuditDigest |
1814 | | //*** CommandAudit() |
1815 | | // This function updates the command audit digest. |
1816 | | static void CommandAudit(COMMAND* command // IN: |
1817 | | ) |
1818 | 127 | { |
1819 | | // If the digest.size is one, it indicates the special case of changing |
1820 | | // the audit hash algorithm. For this case, no audit is done on exit. |
1821 | | // NOTE: When the hash algorithm is changed, g_updateNV is set in order to |
1822 | | // force an update to the NV on exit so that the change in digest will |
1823 | | // be recorded. So, it is safe to exit here without setting any flags |
1824 | | // because the digest change will be written to NV when this code exits. |
1825 | 127 | if(gr.commandAuditDigest.t.size == 1) |
1826 | 1 | { |
1827 | 1 | gr.commandAuditDigest.t.size = 0; |
1828 | 1 | return; |
1829 | 1 | } |
1830 | | // If the digest size is zero, need to start a new digest and increment |
1831 | | // the audit counter. |
1832 | 126 | if(gr.commandAuditDigest.t.size == 0) |
1833 | 126 | { |
1834 | 126 | gr.commandAuditDigest.t.size = CryptHashGetDigestSize(gp.auditHashAlg); |
1835 | 126 | MemorySet(gr.commandAuditDigest.t.buffer, 0, gr.commandAuditDigest.t.size); |
1836 | | |
1837 | | // Bump the counter and save its value to NV. |
1838 | 126 | gp.auditCounter++; |
1839 | 126 | NV_SYNC_PERSISTENT(auditCounter); |
1840 | 126 | } |
1841 | 126 | UpdateAuditDigest(command, gp.auditHashAlg, &gr.commandAuditDigest); |
1842 | 126 | return; |
1843 | 127 | } |
1844 | | #endif |
1845 | | |
1846 | | //*** UpdateAuditSessionStatus() |
1847 | | // This function updates the internal audit related states of a session. It will: |
1848 | | // a) initialize the session as audit session and set it to be exclusive if this |
1849 | | // is the first time it is used for audit or audit reset was requested; |
1850 | | // b) report exclusive audit session; |
1851 | | // c) extend audit log; and |
1852 | | // d) clear exclusive audit session if no audit session found in the command. |
1853 | | static void UpdateAuditSessionStatus( |
1854 | | COMMAND* command // IN: primary control structure |
1855 | | ) |
1856 | 9.57k | { |
1857 | 9.57k | UINT32 i; |
1858 | 9.57k | TPM_HANDLE auditSession = TPM_RH_UNASSIGNED; |
1859 | | // |
1860 | | // Iterate through sessions |
1861 | 10.4k | for(i = 0; i < command->sessionNum; i++) |
1862 | 894 | { |
1863 | 894 | SESSION* session; |
1864 | | // |
1865 | | // PW session do not have a loaded session and can not be an audit |
1866 | | // session either. Skip it. |
1867 | 894 | if(s_sessionHandles[i] == TPM_RS_PW) |
1868 | 894 | continue; |
1869 | 0 | session = SessionGet(s_sessionHandles[i]); |
1870 | | |
1871 | | // If a session is used for audit |
1872 | 0 | if(IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, audit)) |
1873 | 0 | { |
1874 | | // An audit session has been found |
1875 | 0 | auditSession = s_sessionHandles[i]; |
1876 | | |
1877 | | // If the session has not been an audit session yet, or |
1878 | | // the auditSetting bits indicate a reset, initialize it and set |
1879 | | // it to be the exclusive session |
1880 | 0 | if(session->attributes.isAudit == CLEAR |
1881 | 0 | || IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditReset)) |
1882 | 0 | { |
1883 | 0 | InitAuditSession(session); |
1884 | 0 | g_exclusiveAuditSession = auditSession; |
1885 | 0 | } |
1886 | 0 | else |
1887 | 0 | { |
1888 | | // Check if the audit session is the current exclusive audit |
1889 | | // session and, if not, clear previous exclusive audit session. |
1890 | 0 | if(g_exclusiveAuditSession != auditSession) |
1891 | 0 | g_exclusiveAuditSession = TPM_RH_UNASSIGNED; |
1892 | 0 | } |
1893 | | // Report audit session exclusivity. |
1894 | 0 | if(g_exclusiveAuditSession == auditSession) |
1895 | 0 | { |
1896 | 0 | SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive); |
1897 | 0 | } |
1898 | 0 | else |
1899 | 0 | { |
1900 | 0 | CLEAR_ATTRIBUTE(s_attributes[i], TPMA_SESSION, auditExclusive); |
1901 | 0 | } |
1902 | | // Extend audit log. |
1903 | 0 | Audit(command, session); |
1904 | 0 | } |
1905 | 0 | } |
1906 | | // If no audit session is found in the command, and the command allows |
1907 | | // a session then, clear the current exclusive |
1908 | | // audit session. |
1909 | 9.57k | if(auditSession == TPM_RH_UNASSIGNED && IsSessionAllowed(command->index)) |
1910 | 2.45k | { |
1911 | 2.45k | g_exclusiveAuditSession = TPM_RH_UNASSIGNED; |
1912 | 2.45k | } |
1913 | 9.57k | return; |
1914 | 9.57k | } |
1915 | | |
1916 | | //*** ComputeResponseHMAC() |
1917 | | // Function to compute HMAC for authorization session in a response. |
1918 | | /*(See part 1 specification) |
1919 | | // Function: Compute HMAC for response sessions |
1920 | | // The sessionAuth value |
1921 | | // authHMAC := HMACsHASH((sessionAuth | authValue), |
1922 | | // (pHash | nonceTPM | nonceCaller | sessionAttributes)) |
1923 | | // Where: |
1924 | | // HMACsHASH() The HMAC algorithm using the hash algorithm specified when |
1925 | | // the session was started. |
1926 | | // |
1927 | | // sessionAuth A TPMB_MEDIUM computed in a protocol-dependent way, using |
1928 | | // KDFa. In an HMAC or KDF, only sessionAuth.buffer is used. |
1929 | | // |
1930 | | // authValue A TPM2B_AUTH that is found in the sensitive area of an |
1931 | | // object. In an HMAC or KDF, only authValue.buffer is used |
1932 | | // and all trailing zeros are removed. |
1933 | | // |
1934 | | // pHash Response parameters (rpHash) using the session hash. When |
1935 | | // using a pHash in an HMAC computation, both the algorithm ID |
1936 | | // and the digest are included. |
1937 | | // |
1938 | | // nonceTPM A TPM2B_NONCE that is generated by the entity using the |
1939 | | // session. In an HMAC or KDF, only nonceTPM.buffer is used. |
1940 | | // |
1941 | | // nonceCaller a TPM2B_NONCE that was received the previous time the |
1942 | | // session was used. In an HMAC or KDF, only |
1943 | | // nonceCaller.buffer is used. |
1944 | | // |
1945 | | // sessionAttributes A TPMA_SESSION that indicates the attributes associated |
1946 | | // with a particular use of the session. |
1947 | | */ |
1948 | | static void ComputeResponseHMAC( |
1949 | | COMMAND* command, // IN: command structure |
1950 | | UINT32 sessionIndex, // IN: session index to be processed |
1951 | | SESSION* session, // IN: loaded session |
1952 | | TPM2B_DIGEST* hmac // OUT: authHMAC |
1953 | | ) |
1954 | 0 | { |
1955 | 0 | TPM2B_TYPE(KEY, (sizeof(AUTH_VALUE) * 2)); |
1956 | 0 | TPM2B_KEY key; // HMAC key |
1957 | 0 | BYTE marshalBuffer[sizeof(TPMA_SESSION)]; |
1958 | 0 | BYTE* buffer; |
1959 | 0 | UINT32 marshalSize; |
1960 | 0 | HMAC_STATE hmacState; |
1961 | 0 | TPM2B_DIGEST* rpHash = ComputeRpHash(command, session->authHashAlg); |
1962 | | // |
1963 | | // Generate HMAC key |
1964 | 0 | MemoryCopy2B(&key.b, &session->sessionKey.b, sizeof(key.t.buffer)); |
1965 | | |
1966 | | // Add the object authValue if required |
1967 | 0 | if(session->attributes.includeAuth == SET) |
1968 | 0 | { |
1969 | | // Note: includeAuth may be SET for a policy that is used in |
1970 | | // UndefineSpaceSpecial(). At this point, the Index has been deleted |
1971 | | // so the includeAuth will have no meaning. However, the |
1972 | | // s_associatedHandles[] value for the session is now set to TPM_RH_NULL so |
1973 | | // this will return the authValue associated with TPM_RH_NULL and that is |
1974 | | // and empty buffer. |
1975 | 0 | TPM2B_AUTH authValue; |
1976 | | // |
1977 | | // Get the authValue with trailing zeros removed |
1978 | 0 | EntityGetAuthValue(s_associatedHandles[sessionIndex], &authValue); |
1979 | | |
1980 | | // Add it to the key |
1981 | 0 | MemoryConcat2B(&key.b, &authValue.b, sizeof(key.t.buffer)); |
1982 | 0 | } |
1983 | | |
1984 | | // if the HMAC key size is 0, the response HMAC is computed according to the |
1985 | | // input HMAC |
1986 | 0 | if(key.t.size == 0 && s_inputAuthValues[sessionIndex].t.size == 0) |
1987 | 0 | { |
1988 | 0 | hmac->t.size = 0; |
1989 | 0 | return; |
1990 | 0 | } |
1991 | | // Start HMAC computation. |
1992 | 0 | hmac->t.size = CryptHmacStart2B(&hmacState, session->authHashAlg, &key.b); |
1993 | | |
1994 | | // Add hash components. |
1995 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &rpHash->b); |
1996 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &session->nonceTPM.b); |
1997 | 0 | CryptDigestUpdate2B(&hmacState.hashState, &s_nonceCaller[sessionIndex].b); |
1998 | | |
1999 | | // Add session attributes. |
2000 | 0 | buffer = marshalBuffer; |
2001 | 0 | marshalSize = TPMA_SESSION_Marshal(&s_attributes[sessionIndex], &buffer, NULL); |
2002 | 0 | CryptDigestUpdate(&hmacState.hashState, marshalSize, marshalBuffer); |
2003 | | |
2004 | | // Finalize HMAC. |
2005 | 0 | CryptHmacEnd2B(&hmacState, &hmac->b); |
2006 | |
|
2007 | 0 | return; |
2008 | 0 | } |
2009 | | |
2010 | | //*** UpdateInternalSession() |
2011 | | // This function updates internal sessions by: |
2012 | | // a) restarting session time; and |
2013 | | // b) clearing a policy session since nonce is rolling. |
2014 | | static void UpdateInternalSession(SESSION* session, // IN: the session structure |
2015 | | UINT32 i // IN: session number |
2016 | | ) |
2017 | 0 | { |
2018 | | // If nonce is rolling in a policy session, the policy related data |
2019 | | // will be re-initialized. |
2020 | 0 | if(HandleGetType(s_sessionHandles[i]) == TPM_HT_POLICY_SESSION |
2021 | 0 | && IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession)) |
2022 | 0 | { |
2023 | | // When the nonce rolls it starts a new timing interval for the |
2024 | | // policy session. |
2025 | 0 | SessionResetPolicyData(session); |
2026 | 0 | SessionSetStartTime(session); |
2027 | 0 | } |
2028 | 0 | return; |
2029 | 0 | } |
2030 | | |
2031 | | //*** BuildSingleResponseAuth() |
2032 | | // Function to compute response HMAC value for a policy or HMAC session. |
2033 | | static TPM2B_NONCE* BuildSingleResponseAuth( |
2034 | | COMMAND* command, // IN: command structure |
2035 | | UINT32 sessionIndex, // IN: session index to be processed |
2036 | | TPM2B_AUTH* auth // OUT: authHMAC |
2037 | | ) |
2038 | 0 | { |
2039 | | // Fill in policy/HMAC based session response. |
2040 | 0 | SESSION* session = SessionGet(s_sessionHandles[sessionIndex]); |
2041 | | // |
2042 | | // If the session is a policy session with isPasswordNeeded SET, the |
2043 | | // authorization field is empty. |
2044 | 0 | if(HandleGetType(s_sessionHandles[sessionIndex]) == TPM_HT_POLICY_SESSION |
2045 | 0 | && session->attributes.isPasswordNeeded == SET) |
2046 | 0 | auth->t.size = 0; |
2047 | 0 | else |
2048 | | // Compute response HMAC. |
2049 | 0 | ComputeResponseHMAC(command, sessionIndex, session, auth); |
2050 | |
|
2051 | 0 | UpdateInternalSession(session, sessionIndex); |
2052 | 0 | return &session->nonceTPM; |
2053 | 0 | } |
2054 | | |
2055 | | //*** UpdateAllNonceTPM() |
2056 | | // Updates TPM nonce for all sessions in command. |
2057 | | static void UpdateAllNonceTPM(COMMAND* command // IN: controlling structure |
2058 | | ) |
2059 | 894 | { |
2060 | 894 | UINT32 i; |
2061 | 894 | SESSION* session; |
2062 | | // |
2063 | 1.78k | for(i = 0; i < command->sessionNum; i++) |
2064 | 894 | { |
2065 | | // If not a PW session, compute the new nonceTPM. |
2066 | 894 | if(s_sessionHandles[i] != TPM_RS_PW) |
2067 | 0 | { |
2068 | 0 | session = SessionGet(s_sessionHandles[i]); |
2069 | | // Update nonceTPM in both internal session and response. |
2070 | 0 | CryptRandomGenerate(session->nonceTPM.t.size, session->nonceTPM.t.buffer); |
2071 | 0 | } |
2072 | 894 | } |
2073 | 894 | return; |
2074 | 894 | } |
2075 | | |
2076 | | //*** BuildResponseSession() |
2077 | | // Function to build Session buffer in a response. The authorization data is added |
2078 | | // to the end of command->responseBuffer. The size of the authorization area is |
2079 | | // accumulated in command->authSize. |
2080 | | // When this is called, command->responseBuffer is pointing at the next location |
2081 | | // in the response buffer to be filled. This is where the authorization sessions |
2082 | | // will go, if any. command->parameterSize is the number of bytes that have been |
2083 | | // marshaled as parameters in the output buffer. |
2084 | | TPM_RC |
2085 | | BuildResponseSession(COMMAND* command // IN: structure that has relevant command |
2086 | | // information |
2087 | | ) |
2088 | 9.57k | { |
2089 | 9.57k | TPM_RC result = TPM_RC_SUCCESS; |
2090 | | |
2091 | 9.57k | pAssert(command->authSize == 0); |
2092 | | |
2093 | | // Reset the parameter buffer to point to the start of the parameters so that |
2094 | | // there is a starting point for any rpHash that might be generated and so there |
2095 | | // is a place where parameter encryption would start |
2096 | 9.57k | command->parameterBuffer = command->responseBuffer - command->parameterSize; |
2097 | | |
2098 | | // Session nonces should be updated before parameter encryption |
2099 | 9.57k | if(command->tag == TPM_ST_SESSIONS) |
2100 | 894 | { |
2101 | 894 | UpdateAllNonceTPM(command); |
2102 | | |
2103 | | // Encrypt first parameter if applicable. Parameter encryption should |
2104 | | // happen after nonce update and before any rpHash is computed. |
2105 | | // If the encrypt session is associated with a handle, the authValue of |
2106 | | // this handle will be concatenated with sessionKey to generate |
2107 | | // encryption key, no matter if the handle is the session bound entity |
2108 | | // or not. The authValue is added to sessionKey only when the authValue |
2109 | | // is available. |
2110 | 894 | if(s_encryptSessionIndex != UNDEFINED_INDEX) |
2111 | 0 | { |
2112 | 0 | UINT32 size; |
2113 | 0 | TPM2B_AUTH extraKey; |
2114 | | // |
2115 | 0 | extraKey.b.size = 0; |
2116 | | // If this is an authorization session, include the authValue in the |
2117 | | // generation of the encryption key |
2118 | 0 | if(s_associatedHandles[s_encryptSessionIndex] != TPM_RH_UNASSIGNED) |
2119 | 0 | { |
2120 | 0 | EntityGetAuthValue(s_associatedHandles[s_encryptSessionIndex], |
2121 | 0 | &extraKey); |
2122 | 0 | } |
2123 | 0 | size = EncryptSize(command->index); |
2124 | | // This function operates on internally-generated data that is |
2125 | | // expected to be well-formed for parameter encryption. |
2126 | | // In the event that there is a bug elsewhere in the code and the |
2127 | | // input data is not well-formed, CryptParameterEncryption will |
2128 | | // put the TPM into failure mode instead of allowing the out-of- |
2129 | | // band write. |
2130 | 0 | CryptParameterEncryption(s_sessionHandles[s_encryptSessionIndex], |
2131 | 0 | &s_nonceCaller[s_encryptSessionIndex].b, |
2132 | 0 | command->parameterSize, |
2133 | 0 | (UINT16)size, |
2134 | 0 | &extraKey, |
2135 | 0 | command->parameterBuffer); |
2136 | 0 | if(g_inFailureMode) |
2137 | 0 | { |
2138 | 0 | result = TPM_RC_FAILURE; |
2139 | 0 | goto Cleanup; |
2140 | 0 | } |
2141 | 0 | } |
2142 | 894 | } |
2143 | | // Audit sessions should be processed regardless of the tag because |
2144 | | // a command with no session may cause a change of the exclusivity state. |
2145 | 9.57k | UpdateAuditSessionStatus(command); |
2146 | 9.57k | #if CC_GetCommandAuditDigest |
2147 | | // Command Audit |
2148 | 9.57k | if(CommandAuditIsRequired(command->index)) |
2149 | 127 | CommandAudit(command); |
2150 | 9.57k | #endif |
2151 | | // Process command with sessions. |
2152 | 9.57k | if(command->tag == TPM_ST_SESSIONS) |
2153 | 894 | { |
2154 | 894 | UINT32 i; |
2155 | | // |
2156 | 894 | pAssert(command->sessionNum > 0); |
2157 | | |
2158 | | // Iterate over each session in the command session area, and create |
2159 | | // corresponding sessions for response. |
2160 | 1.78k | for(i = 0; i < command->sessionNum; i++) |
2161 | 894 | { |
2162 | 894 | TPM2B_NONCE* nonceTPM; |
2163 | 894 | TPM2B_DIGEST responseAuth; |
2164 | | // Make sure that continueSession is SET on any Password session. |
2165 | | // This makes it marginally easier for the management software |
2166 | | // to keep track of the closed sessions. |
2167 | 894 | if(s_sessionHandles[i] == TPM_RS_PW) |
2168 | 894 | { |
2169 | 894 | SET_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession); |
2170 | 894 | responseAuth.t.size = 0; |
2171 | 894 | nonceTPM = (TPM2B_NONCE*)&responseAuth; |
2172 | 894 | } |
2173 | 0 | else |
2174 | 0 | { |
2175 | | // Compute the response HMAC and get a pointer to the nonce used. |
2176 | | // This function will also update the values if needed. Note, the |
2177 | 0 | nonceTPM = BuildSingleResponseAuth(command, i, &responseAuth); |
2178 | 0 | } |
2179 | 894 | command->authSize += |
2180 | 894 | TPM2B_NONCE_Marshal(nonceTPM, &command->responseBuffer, NULL); |
2181 | 894 | command->authSize += TPMA_SESSION_Marshal( |
2182 | 894 | &s_attributes[i], &command->responseBuffer, NULL); |
2183 | 894 | command->authSize += |
2184 | 894 | TPM2B_DIGEST_Marshal(&responseAuth, &command->responseBuffer, NULL); |
2185 | 894 | if(!IS_ATTRIBUTE(s_attributes[i], TPMA_SESSION, continueSession)) |
2186 | 0 | SessionFlush(s_sessionHandles[i]); |
2187 | 894 | } |
2188 | 894 | } |
2189 | | |
2190 | 9.57k | Cleanup: |
2191 | 9.57k | return result; |
2192 | 9.57k | } |
2193 | | |
2194 | | //*** SessionRemoveAssociationToHandle() |
2195 | | // This function deals with the case where an entity associated with an authorization |
2196 | | // is deleted during command processing. The primary use of this is to support |
2197 | | // UndefineSpaceSpecial(). |
2198 | | void SessionRemoveAssociationToHandle(TPM_HANDLE handle) |
2199 | 0 | { |
2200 | 0 | UINT32 i; |
2201 | | // |
2202 | 0 | for(i = 0; i < MAX_SESSION_NUM; i++) |
2203 | 0 | { |
2204 | 0 | if(s_associatedHandles[i] == HierarchyNormalizeHandle(handle)) |
2205 | 0 | { |
2206 | 0 | s_associatedHandles[i] = TPM_RH_NULL; |
2207 | 0 | } |
2208 | 0 | } |
2209 | 0 | } |