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