Line | Count | Source (jump to first uncovered line) |
1 | | // This file was extracted from the TCG Published |
2 | | // Trusted Platform Module Library |
3 | | // Part 4: Supporting Routines |
4 | | // Family "2.0" |
5 | | // Level 00 Revision 01.16 |
6 | | // October 30, 2014 |
7 | | |
8 | | #define SESSION_C |
9 | | #include "InternalRoutines.h" |
10 | | #include "Platform.h" |
11 | | #include "SessionProcess_fp.h" |
12 | | // |
13 | | // |
14 | | // File Scope Function -- ContextIdSetOldest() |
15 | | // |
16 | | // This function is called when the oldest contextID is being loaded or deleted. Once a saved context |
17 | | // becomes the oldest, it stays the oldest until it is deleted. |
18 | | // Finding the oldest is a bit tricky. It is not just the numeric comparison of values but is dependent on the |
19 | | // value of contextCounter. |
20 | | // Assume we have a small contextArray with 8, 4-bit values with values 1 and 2 used to indicate the loaded |
21 | | // context slot number. Also assume that the array contains hex values of (0 0 1 0 3 0 9 F) and that the |
22 | | // contextCounter is an 8-bit counter with a value of 0x37. Since the low nibble is 7, that means that values |
23 | | // above 7 are older than values below it and, in this example, 9 is the oldest value. |
24 | | // Note if we subtract the counter value, from each slot that contains a saved contextID we get (- - - - B - 2 - |
25 | | // 8) and the oldest entry is now easy to find. |
26 | | // |
27 | | static void |
28 | | ContextIdSetOldest( |
29 | | void |
30 | | ) |
31 | 0 | { |
32 | 0 | CONTEXT_SLOT lowBits; |
33 | 0 | CONTEXT_SLOT entry; |
34 | 0 | CONTEXT_SLOT smallest = ((CONTEXT_SLOT) ~0); |
35 | 0 | UINT32 i; |
36 | | // |
37 | | // Set oldestSaveContext to a value indicating none assigned |
38 | 0 | s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; |
39 | 0 | lowBits = (CONTEXT_SLOT)gr.contextCounter; |
40 | 0 | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
41 | 0 | { |
42 | 0 | entry = gr.contextArray[i]; |
43 | | // only look at entries that are saved contexts |
44 | 0 | if(entry > MAX_LOADED_SESSIONS) |
45 | 0 | { |
46 | | // Use a less than or equal in case the oldest |
47 | | // is brand new (= lowBits-1) and equal to our initial |
48 | | // value for smallest. |
49 | 0 | if(((CONTEXT_SLOT) (entry - lowBits)) <= smallest) |
50 | 0 | { |
51 | 0 | smallest = (entry - lowBits); |
52 | 0 | s_oldestSavedSession = i; |
53 | 0 | } |
54 | 0 | } |
55 | 0 | } |
56 | | // When we finish, either the s_oldestSavedSession still has its initial |
57 | | // value, or it has the index of the oldest saved context. |
58 | 0 | } |
59 | | // |
60 | | // |
61 | | // Startup Function -- SessionStartup() |
62 | | // |
63 | | // This function initializes the session subsystem on TPM2_Startup(). |
64 | | // |
65 | | void |
66 | | SessionStartup( |
67 | | STARTUP_TYPE type |
68 | | ) |
69 | 5.63k | { |
70 | 5.63k | UINT32 i; |
71 | | // Initialize session slots. At startup, all the in-memory session slots |
72 | | // are cleared and marked as not occupied |
73 | 22.5k | for(i = 0; i < MAX_LOADED_SESSIONS; i++) |
74 | 16.9k | s_sessions[i].occupied = FALSE; // session slot is not occupied |
75 | | // The free session slots the number of maximum allowed loaded sessions |
76 | 5.63k | s_freeSessionSlots = MAX_LOADED_SESSIONS; |
77 | | // Initialize context ID data. On a ST_SAVE or hibernate sequence, it will |
78 | | // scan the saved array of session context counts, and clear any entry that |
79 | | // references a session that was in memory during the state save since that |
80 | | // memory was not preserved over the ST_SAVE. |
81 | 5.63k | if(type == SU_RESUME || type == SU_RESTART) |
82 | 0 | { |
83 | | // On ST_SAVE we preserve the contexts that were saved but not the ones |
84 | | // in memory |
85 | 0 | for (i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
86 | 0 | { |
87 | | // If the array value is unused or references a loaded session then |
88 | | // that loaded session context is lost and the array entry is |
89 | | // reclaimed. |
90 | 0 | if (gr.contextArray[i] <= MAX_LOADED_SESSIONS) |
91 | 0 | gr.contextArray[i] = 0; |
92 | 0 | } |
93 | | // Find the oldest session in context ID data and set it in |
94 | | // s_oldestSavedSession |
95 | 0 | ContextIdSetOldest(); |
96 | | // |
97 | 0 | } |
98 | 5.63k | else |
99 | 5.63k | { |
100 | | // For STARTUP_CLEAR, clear out the contextArray |
101 | 366k | for (i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
102 | 360k | gr.contextArray[i] = 0; |
103 | | // reset the context counter |
104 | 5.63k | gr.contextCounter = MAX_LOADED_SESSIONS + 1; |
105 | | // Initialize oldest saved session |
106 | 5.63k | s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; |
107 | 5.63k | } |
108 | 5.63k | return; |
109 | 5.63k | } |
110 | | // |
111 | | // |
112 | | // Access Functions |
113 | | // |
114 | | // SessionIsLoaded() |
115 | | // |
116 | | // This function test a session handle references a loaded session. The handle must have previously been |
117 | | // checked to make sure that it is a valid handle for an authorization session. |
118 | | // |
119 | | // NOTE: A PWAP authorization does not have a session. |
120 | | // |
121 | | // |
122 | | // Return Value Meaning |
123 | | // |
124 | | // TRUE if session is loaded |
125 | | // FALSE if it is not loaded |
126 | | // |
127 | | BOOL |
128 | | SessionIsLoaded( |
129 | | TPM_HANDLE handle // IN: session handle |
130 | | ) |
131 | 32 | { |
132 | 32 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
133 | 32 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION); |
134 | 32 | handle = handle & HR_HANDLE_MASK; |
135 | | // if out of range of possible active session, or not assigned to a loaded |
136 | | // session return false |
137 | 32 | if( handle >= MAX_ACTIVE_SESSIONS |
138 | 32 | || gr.contextArray[handle] == 0 |
139 | 32 | || gr.contextArray[handle] > MAX_LOADED_SESSIONS |
140 | 32 | ) |
141 | 32 | return FALSE; |
142 | 0 | return TRUE; |
143 | 32 | } |
144 | | // |
145 | | // |
146 | | // SessionIsSaved() |
147 | | // |
148 | | // This function test a session handle references a saved session. The handle must have previously been |
149 | | // checked to make sure that it is a valid handle for an authorization session. |
150 | | // |
151 | | // NOTE: An password authorization does not have a session. |
152 | | // |
153 | | // This function requires that the handle be a valid session handle. |
154 | | // |
155 | | // |
156 | | // Return Value Meaning |
157 | | // |
158 | | // TRUE if session is saved |
159 | | // FALSE if it is not saved |
160 | | // |
161 | | BOOL |
162 | | SessionIsSaved( |
163 | | TPM_HANDLE handle // IN: session handle |
164 | | ) |
165 | 11 | { |
166 | 11 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
167 | 11 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION); |
168 | 11 | handle = handle & HR_HANDLE_MASK; |
169 | | // if out of range of possible active session, or not assigned, or |
170 | | // assigned to a loaded session, return false |
171 | 11 | if( handle >= MAX_ACTIVE_SESSIONS |
172 | 11 | || gr.contextArray[handle] == 0 |
173 | 11 | || gr.contextArray[handle] <= MAX_LOADED_SESSIONS |
174 | 11 | ) |
175 | 11 | return FALSE; |
176 | 0 | return TRUE; |
177 | 11 | } |
178 | | // |
179 | | // |
180 | | // SessionPCRValueIsCurrent() |
181 | | // |
182 | | // This function is used to check if PCR values have been updated since the last time they were checked in |
183 | | // a policy session. |
184 | | // This function requires the session is loaded. |
185 | | // |
186 | | // Return Value Meaning |
187 | | // |
188 | | // TRUE if PCR value is current |
189 | | // FALSE if PCR value is not current |
190 | | // |
191 | | BOOL |
192 | | SessionPCRValueIsCurrent( |
193 | | TPMI_SH_POLICY handle // IN: session handle |
194 | | ) |
195 | 0 | { |
196 | 0 | SESSION *session; |
197 | 0 | pAssert(SessionIsLoaded(handle)); |
198 | 0 | session = SessionGet(handle); |
199 | 0 | if( session->pcrCounter != 0 |
200 | 0 | && session->pcrCounter != gr.pcrCounter |
201 | 0 | ) |
202 | 0 | return FALSE; |
203 | 0 | else |
204 | 0 | return TRUE; |
205 | 0 | } |
206 | | // |
207 | | // |
208 | | // SessionGet() |
209 | | // |
210 | | // This function returns a pointer to the session object associated with a session handle. |
211 | | // The function requires that the session is loaded. |
212 | | // |
213 | | SESSION * |
214 | | SessionGet( |
215 | | TPM_HANDLE handle // IN: session handle |
216 | | ) |
217 | 15 | { |
218 | 15 | CONTEXT_SLOT sessionIndex; |
219 | 15 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
220 | 15 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION |
221 | 15 | ); |
222 | 15 | pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); |
223 | | // get the contents of the session array. Because session is loaded, we |
224 | | // should always get a valid sessionIndex |
225 | 15 | sessionIndex = gr.contextArray[handle & HR_HANDLE_MASK] - 1; |
226 | 15 | pAssert(sessionIndex < MAX_LOADED_SESSIONS); |
227 | 15 | return &s_sessions[sessionIndex].session; |
228 | 15 | } |
229 | | // |
230 | | // |
231 | | // Utility Functions |
232 | | // |
233 | | // ContextIdSessionCreate() |
234 | | // |
235 | | // This function is called when a session is created. It will check to see if the current gap would prevent a |
236 | | // context from being saved. If so it will return TPM_RC_CONTEXT_GAP. Otherwise, it will try to find an |
237 | | // open slot in contextArray, set contextArray to the slot. |
238 | | // This routine requires that the caller has determined the session array index for the session. |
239 | | // |
240 | | // return type TPM_RC |
241 | | // |
242 | | // TPM_RC_SUCCESS context ID was assigned |
243 | | // TPM_RC_CONTEXT_GAP can't assign a new contextID until the oldest saved session context is |
244 | | // recycled |
245 | | // TPM_RC_SESSION_HANDLE there is no slot available in the context array for tracking of this |
246 | | // session context |
247 | | // |
248 | | static TPM_RC |
249 | | ContextIdSessionCreate ( |
250 | | TPM_HANDLE *handle, // OUT: receives the assigned handle. This will |
251 | | // be an index that must be adjusted by the |
252 | | // caller according to the type of the |
253 | | // session created |
254 | | UINT32 sessionIndex // IN: The session context array entry that will |
255 | | // be occupied by the created session |
256 | | ) |
257 | 15 | { |
258 | 15 | pAssert(sessionIndex < MAX_LOADED_SESSIONS); |
259 | | // check to see if creating the context is safe |
260 | | // Is this going to be an assignment for the last session context |
261 | | // array entry? If so, then there will be no room to recycle the |
262 | | // oldest context if needed. If the gap is not at maximum, then |
263 | | // it will be possible to save a context if it becomes necessary. |
264 | 15 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
265 | 15 | && s_freeSessionSlots == 1) |
266 | 0 | { |
267 | | // See if the gap is at maximum |
268 | 0 | if( (CONTEXT_SLOT)gr.contextCounter |
269 | 0 | == gr.contextArray[s_oldestSavedSession]) |
270 | | // Note: if this is being used on a TPM.combined, this return |
271 | | // code should be transformed to an appropriate 1.2 error |
272 | | // code for this case. |
273 | 0 | return TPM_RC_CONTEXT_GAP; |
274 | 0 | } |
275 | | // Find an unoccupied entry in the contextArray |
276 | 15 | for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++) |
277 | 15 | { |
278 | 15 | if(gr.contextArray[*handle] == 0) |
279 | 15 | { |
280 | | // indicate that the session associated with this handle |
281 | | // references a loaded session |
282 | 15 | gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex+1); |
283 | 15 | return TPM_RC_SUCCESS; |
284 | 15 | } |
285 | 15 | } |
286 | 0 | return TPM_RC_SESSION_HANDLES; |
287 | 15 | } |
288 | | // |
289 | | // |
290 | | // SessionCreate() |
291 | | // |
292 | | // This function does the detailed work for starting an authorization session. This is done in a support |
293 | | // routine rather than in the action code because the session management may differ in implementations. |
294 | | // This implementation uses a fixed memory allocation to hold sessions and a fixed allocation to hold the |
295 | | // contextID for the saved contexts. |
296 | | // |
297 | | // Error Returns Meaning |
298 | | // |
299 | | // TPM_RC_CONTEXT_GAP need to recycle sessions |
300 | | // TPM_RC_SESSION_HANDLE active session space is full |
301 | | // TPM_RC_SESSION_MEMORY loaded session space is full |
302 | | // |
303 | | TPM_RC |
304 | | SessionCreate( |
305 | | TPM_SE sessionType, // IN: the session type |
306 | | TPMI_ALG_HASH authHash, // IN: the hash algorithm |
307 | | TPM2B_NONCE *nonceCaller, // IN: initial nonceCaller |
308 | | TPMT_SYM_DEF *symmetric, // IN: the symmetric algorithm |
309 | | TPMI_DH_ENTITY bind, // IN: the bind object |
310 | | TPM2B_DATA *seed, // IN: seed data |
311 | | TPM_HANDLE *sessionHandle // OUT: the session handle |
312 | | ) |
313 | 15 | { |
314 | 15 | TPM_RC result = TPM_RC_SUCCESS; |
315 | 15 | CONTEXT_SLOT slotIndex; |
316 | 15 | SESSION *session = NULL; |
317 | 15 | pAssert( sessionType == TPM_SE_HMAC |
318 | 15 | || sessionType == TPM_SE_POLICY |
319 | 15 | || sessionType == TPM_SE_TRIAL); |
320 | | // If there are no open spots in the session array, then no point in searching |
321 | 15 | if(s_freeSessionSlots == 0) |
322 | 0 | return TPM_RC_SESSION_MEMORY; |
323 | | // Find a space for loading a session |
324 | 15 | for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++) |
325 | 15 | { |
326 | | // Is this available? |
327 | 15 | if(s_sessions[slotIndex].occupied == FALSE) |
328 | 15 | { |
329 | 15 | session = &s_sessions[slotIndex].session; |
330 | 15 | break; |
331 | 15 | } |
332 | 15 | } |
333 | | // if no spot found, then this is an internal error |
334 | 15 | pAssert (slotIndex < MAX_LOADED_SESSIONS); |
335 | | // Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be |
336 | | // returned from ContextIdHandelAssign() |
337 | 15 | result = ContextIdSessionCreate(sessionHandle, slotIndex); |
338 | 15 | if(result != TPM_RC_SUCCESS) |
339 | 0 | return result; |
340 | | //*** Only return from this point on is TPM_RC_SUCCESS |
341 | | // Can now indicate that the session array entry is occupied. |
342 | 15 | s_freeSessionSlots--; |
343 | 15 | s_sessions[slotIndex].occupied = TRUE; |
344 | | // Initialize the session data |
345 | 15 | MemorySet(session, 0, sizeof(SESSION)); |
346 | | // Initialize internal session data |
347 | 15 | session->authHashAlg = authHash; |
348 | | // Initialize session type |
349 | 15 | if(sessionType == TPM_SE_HMAC) |
350 | 10 | { |
351 | 10 | *sessionHandle += HMAC_SESSION_FIRST; |
352 | 10 | } |
353 | 5 | else |
354 | 5 | { |
355 | 5 | *sessionHandle += POLICY_SESSION_FIRST; |
356 | | // For TPM_SE_POLICY or TPM_SE_TRIAL |
357 | 5 | session->attributes.isPolicy = SET; |
358 | 5 | if(sessionType == TPM_SE_TRIAL) |
359 | 2 | session->attributes.isTrialPolicy = SET; |
360 | | // Initialize policy session data |
361 | 5 | SessionInitPolicyData(session); |
362 | 5 | } |
363 | | // Create initial session nonce |
364 | 15 | session->nonceTPM.t.size = nonceCaller->t.size; |
365 | 15 | CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer); |
366 | | // Set up session parameter encryption algorithm |
367 | 15 | session->symmetric = *symmetric; |
368 | | // If there is a bind object or a session secret, then need to compute |
369 | | // a sessionKey. |
370 | 15 | if(bind != TPM_RH_NULL || seed->t.size != 0) |
371 | 14 | { |
372 | | // sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM, |
373 | | // nonceCaller, bits) |
374 | | // The HMAC key for generating the sessionSecret can be the concatenation |
375 | | // of an authorization value and a seed value |
376 | 14 | TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer))); |
377 | 14 | TPM2B_KEY key; |
378 | 14 | UINT16 hashSize; // The size of the hash used by the |
379 | | // session crated by this command |
380 | 14 | TPM2B_AUTH entityAuth; // The authValue of the entity |
381 | | // associated with HMAC session |
382 | | // Get hash size, which is also the length of sessionKey |
383 | 14 | hashSize = CryptGetHashDigestSize(session->authHashAlg); |
384 | | // Get authValue of associated entity |
385 | 14 | entityAuth.t.size = EntityGetAuthValue(bind, &entityAuth.t.buffer); |
386 | | // Concatenate authValue and seed |
387 | 14 | pAssert(entityAuth.t.size + seed->t.size <= sizeof(key.t.buffer)); |
388 | 14 | MemoryCopy2B(&key.b, &entityAuth.b, sizeof(key.t.buffer)); |
389 | 14 | MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer)); |
390 | 14 | session->sessionKey.t.size = hashSize; |
391 | | // Compute the session key |
392 | 14 | KDFa(session->authHashAlg, &key.b, "ATH", &session->nonceTPM.b, |
393 | 14 | &nonceCaller->b, hashSize * 8, session->sessionKey.t.buffer, NULL); |
394 | 14 | } |
395 | | // Copy the name of the entity that the HMAC session is bound to |
396 | | // Policy session is not bound to an entity |
397 | 15 | if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC) |
398 | 9 | { |
399 | 9 | session->attributes.isBound = SET; |
400 | 9 | SessionComputeBoundEntity(bind, &session->u1.boundEntity); |
401 | 9 | } |
402 | | // If there is a bind object and it is subject to DA, then use of this session |
403 | | // is subject to DA regardless of how it is used. |
404 | 15 | session->attributes.isDaBound = (bind != TPM_RH_NULL) |
405 | 15 | && (IsDAExempted(bind) == FALSE); |
406 | | // If the session is bound, then check to see if it is bound to lockoutAuth |
407 | 15 | session->attributes.isLockoutBound = (session->attributes.isDaBound == SET) |
408 | 15 | && (bind == TPM_RH_LOCKOUT); |
409 | 15 | return TPM_RC_SUCCESS; |
410 | 15 | } |
411 | | // |
412 | | // |
413 | | // SessionContextSave() |
414 | | // |
415 | | // This function is called when a session context is to be saved. The contextID of the saved session is |
416 | | // returned. If no contextID can be assigned, then the routine returns TPM_RC_CONTEXT_GAP. If the |
417 | | // function completes normally, the session slot will be freed. |
418 | | // This function requires that handle references a loaded session. Otherwise, it should not be called at the |
419 | | // first place. |
420 | | // |
421 | | // Error Returns Meaning |
422 | | // |
423 | | // TPM_RC_CONTEXT_GAP a contextID could not be assigned. |
424 | | // TPM_RC_TOO_MANY_CONTEXTS the counter maxed out |
425 | | // |
426 | | TPM_RC |
427 | | SessionContextSave ( |
428 | | TPM_HANDLE handle, // IN: session handle |
429 | | CONTEXT_COUNTER *contextID // OUT: assigned contextID |
430 | | ) |
431 | 0 | { |
432 | 0 | UINT32 contextIndex; |
433 | 0 | CONTEXT_SLOT slotIndex; |
434 | 0 | pAssert(SessionIsLoaded(handle)); |
435 | | // check to see if the gap is already maxed out |
436 | | // Need to have a saved session |
437 | 0 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
438 | | // if the oldest saved session has the same value as the low bits |
439 | | // of the contextCounter, then the GAP is maxed out. |
440 | 0 | && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter) |
441 | 0 | return TPM_RC_CONTEXT_GAP; |
442 | | // if the caller wants the context counter, set it |
443 | 0 | if(contextID != NULL) |
444 | 0 | *contextID = gr.contextCounter; |
445 | 0 | pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); |
446 | 0 | contextIndex = handle & HR_HANDLE_MASK; |
447 | | // Extract the session slot number referenced by the contextArray |
448 | | // because we are going to overwrite this with the low order |
449 | | // contextID value. |
450 | 0 | slotIndex = gr.contextArray[contextIndex] - 1; |
451 | | // Set the contextID for the contextArray |
452 | 0 | gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter; |
453 | | // Increment the counter |
454 | 0 | gr.contextCounter++; |
455 | | // In the unlikely event that the 64-bit context counter rolls over... |
456 | 0 | if(gr.contextCounter == 0) |
457 | 0 | { |
458 | | // back it up |
459 | 0 | gr.contextCounter--; |
460 | | // return an error |
461 | 0 | return TPM_RC_TOO_MANY_CONTEXTS; |
462 | 0 | } |
463 | | // if the low-order bits wrapped, need to advance the value to skip over |
464 | | // the values used to indicate that a session is loaded |
465 | 0 | if(((CONTEXT_SLOT)gr.contextCounter) == 0) |
466 | 0 | gr.contextCounter += MAX_LOADED_SESSIONS + 1; |
467 | | // If no other sessions are saved, this is now the oldest. |
468 | 0 | if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS) |
469 | 0 | s_oldestSavedSession = contextIndex; |
470 | | // Mark the session slot as unoccupied |
471 | 0 | s_sessions[slotIndex].occupied = FALSE; |
472 | | // and indicate that there is an additional open slot |
473 | 0 | s_freeSessionSlots++; |
474 | 0 | return TPM_RC_SUCCESS; |
475 | 0 | } |
476 | | // |
477 | | // |
478 | | // SessionContextLoad() |
479 | | // |
480 | | // This function is used to load a session from saved context. The session handle must be for a saved |
481 | | // context. |
482 | | // If the gap is at a maximum, then the only session that can be loaded is the oldest session, otherwise |
483 | | // TPM_RC_CONTEXT_GAP is returned. |
484 | | // This function requires that handle references a valid saved session. |
485 | | // |
486 | | // |
487 | | // |
488 | | // Error Returns Meaning |
489 | | // |
490 | | // TPM_RC_SESSION_MEMORY no free session slots |
491 | | // TPM_RC_CONTEXT_GAP the gap count is maximum and this is not the oldest saved context |
492 | | // |
493 | | TPM_RC |
494 | | SessionContextLoad( |
495 | | SESSION *session, // IN: session structure from saved context |
496 | | TPM_HANDLE *handle // IN/OUT: session handle |
497 | | ) |
498 | 0 | { |
499 | 0 | UINT32 contextIndex; |
500 | 0 | CONTEXT_SLOT slotIndex; |
501 | 0 | pAssert( HandleGetType(*handle) == TPM_HT_POLICY_SESSION |
502 | 0 | || HandleGetType(*handle) == TPM_HT_HMAC_SESSION); |
503 | | // Don't bother looking if no openings |
504 | 0 | if(s_freeSessionSlots == 0) |
505 | 0 | return TPM_RC_SESSION_MEMORY; |
506 | | // Find a free session slot to load the session |
507 | 0 | for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++) |
508 | 0 | if(s_sessions[slotIndex].occupied == FALSE) break; |
509 | | // if no spot found, then this is an internal error |
510 | 0 | pAssert (slotIndex < MAX_LOADED_SESSIONS); |
511 | 0 | contextIndex = *handle & HR_HANDLE_MASK; // extract the index |
512 | | // If there is only one slot left, and the gap is at maximum, the only session |
513 | | // context that we can safely load is the oldest one. |
514 | 0 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
515 | 0 | && s_freeSessionSlots == 1 |
516 | 0 | && (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession] |
517 | 0 | && contextIndex != s_oldestSavedSession |
518 | 0 | ) |
519 | 0 | return TPM_RC_CONTEXT_GAP; |
520 | 0 | pAssert(contextIndex < MAX_ACTIVE_SESSIONS); |
521 | | // set the contextArray value to point to the session slot where |
522 | | // the context is loaded |
523 | 0 | gr.contextArray[contextIndex] = slotIndex + 1; |
524 | | // if this was the oldest context, find the new oldest |
525 | 0 | if(contextIndex == s_oldestSavedSession) |
526 | 0 | ContextIdSetOldest(); |
527 | | // Copy session data to session slot |
528 | 0 | s_sessions[slotIndex].session = *session; |
529 | | // Set session slot as occupied |
530 | 0 | s_sessions[slotIndex].occupied = TRUE; |
531 | | // Reduce the number of open spots |
532 | 0 | s_freeSessionSlots--; |
533 | 0 | return TPM_RC_SUCCESS; |
534 | 0 | } |
535 | | // |
536 | | // |
537 | | // |
538 | | // SessionFlush() |
539 | | // |
540 | | // This function is used to flush a session referenced by its handle. If the session associated with handle is |
541 | | // loaded, the session array entry is marked as available. |
542 | | // This function requires that handle be a valid active session. |
543 | | // |
544 | | void |
545 | | SessionFlush( |
546 | | TPM_HANDLE handle // IN: loaded or saved session handle |
547 | | ) |
548 | 0 | { |
549 | 0 | CONTEXT_SLOT slotIndex; |
550 | 0 | UINT32 contextIndex; // Index into contextArray |
551 | 0 | pAssert( ( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
552 | 0 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION |
553 | 0 | ) |
554 | 0 | && (SessionIsLoaded(handle) || SessionIsSaved(handle)) |
555 | 0 | ); |
556 | | // Flush context ID of this session |
557 | | // Convert handle to an index into the contextArray |
558 | 0 | contextIndex = handle & HR_HANDLE_MASK; |
559 | 0 | pAssert(contextIndex < sizeof(gr.contextArray)/sizeof(gr.contextArray[0])); |
560 | | // Get the current contents of the array |
561 | 0 | slotIndex = gr.contextArray[contextIndex]; |
562 | | // Mark context array entry as available |
563 | 0 | gr.contextArray[contextIndex] = 0; |
564 | | // Is this a saved session being flushed |
565 | 0 | if(slotIndex > MAX_LOADED_SESSIONS) |
566 | 0 | { |
567 | | // Flushing the oldest session? |
568 | 0 | if(contextIndex == s_oldestSavedSession) |
569 | | // If so, find a new value for oldest. |
570 | 0 | ContextIdSetOldest(); |
571 | 0 | } |
572 | 0 | else |
573 | 0 | { |
574 | | // Adjust slot index to point to session array index |
575 | 0 | slotIndex -= 1; |
576 | | // Free session array index |
577 | 0 | s_sessions[slotIndex].occupied = FALSE; |
578 | 0 | s_freeSessionSlots++; |
579 | 0 | } |
580 | 0 | return; |
581 | 0 | } |
582 | | // |
583 | | // |
584 | | // SessionComputeBoundEntity() |
585 | | // |
586 | | // This function computes the binding value for a session. The binding value for a reserved handle is the |
587 | | // handle itself. For all the other entities, the authValue at the time of binding is included to prevent |
588 | | // squatting. For those values, the Name and the authValue are concatenated into the bind buffer. If they |
589 | | // will not both fit, the will be overlapped by XORing() bytes. If XOR is required, the bind value will be full. |
590 | | // |
591 | | void |
592 | | SessionComputeBoundEntity( |
593 | | TPMI_DH_ENTITY entityHandle, // IN: handle of entity |
594 | | TPM2B_NAME *bind // OUT: binding value |
595 | | ) |
596 | 9 | { |
597 | 9 | TPM2B_AUTH auth; |
598 | 9 | INT16 overlap; |
599 | | // Get name |
600 | 9 | bind->t.size = EntityGetName(entityHandle, &bind->t.name); |
601 | | // // The bound value of a reserved handle is the handle itself |
602 | | // if(bind->t.size == sizeof(TPM_HANDLE)) return; |
603 | | // For all the other entities, concatenate the auth value to the name. |
604 | | // Get a local copy of the auth value because some overlapping |
605 | | // may be necessary. |
606 | 9 | auth.t.size = EntityGetAuthValue(entityHandle, &auth.t.buffer); |
607 | 9 | pAssert(auth.t.size <= sizeof(TPMU_HA)); |
608 | | // Figure out if there will be any overlap |
609 | 9 | overlap = bind->t.size + auth.t.size - sizeof(bind->t.name); |
610 | | // There is overlap if the combined sizes are greater than will fit |
611 | 9 | if(overlap > 0) |
612 | 0 | { |
613 | | // The overlap area is at the end of the Name |
614 | 0 | BYTE *result = &bind->t.name[bind->t.size - overlap]; |
615 | 0 | int i; |
616 | | // XOR the auth value into the Name for the overlap area |
617 | 0 | for(i = 0; i < overlap; i++) |
618 | 0 | result[i] ^= auth.t.buffer[i]; |
619 | 0 | } |
620 | 9 | else |
621 | 9 | { |
622 | | // There is no overlap |
623 | 9 | overlap = 0; |
624 | 9 | } |
625 | | //copy the remainder of the authData to the end of the name |
626 | 9 | MemoryCopy(&bind->t.name[bind->t.size], &auth.t.buffer[overlap], |
627 | 9 | auth.t.size - overlap, sizeof(bind->t.name) - bind->t.size); |
628 | | // Increase the size of the bind data by the size of the auth - the overlap |
629 | 9 | bind->t.size += auth.t.size-overlap; |
630 | 9 | return; |
631 | 9 | } |
632 | | // |
633 | | // |
634 | | // SessionInitPolicyData() |
635 | | // |
636 | | // This function initializes the portions of the session policy data that are not set by the allocation of a |
637 | | // session. |
638 | | // |
639 | | void |
640 | | SessionInitPolicyData( |
641 | | SESSION *session // IN: session handle |
642 | | ) |
643 | 5 | { |
644 | | // Initialize start time |
645 | 5 | session->startTime = go.clock; |
646 | | // Initialize policyDigest. policyDigest is initialized with a string of 0 of |
647 | | // session algorithm digest size. Since the policy already contains all zeros |
648 | | // it is only necessary to set the size |
649 | 5 | session->u2.policyDigest.t.size = CryptGetHashDigestSize(session->authHashAlg); |
650 | 5 | return; |
651 | 5 | } |
652 | | // |
653 | | // |
654 | | // SessionResetPolicyData() |
655 | | // |
656 | | // This function is used to reset the policy data without changing the nonce or the start time of the session. |
657 | | // |
658 | | void |
659 | | SessionResetPolicyData( |
660 | | SESSION *session // IN: the session to reset |
661 | | ) |
662 | 0 | { |
663 | 0 | session->commandCode = 0; // No command |
664 | | // No locality selected |
665 | 0 | MemorySet(&session->commandLocality, 0, sizeof(session->commandLocality)); |
666 | | // The cpHash size to zero |
667 | 0 | session->u1.cpHash.b.size = 0; |
668 | | // No timeout |
669 | 0 | session->timeOut = 0; |
670 | | // Reset the pcrCounter |
671 | 0 | session->pcrCounter = 0; |
672 | | // Reset the policy hash |
673 | 0 | MemorySet(&session->u2.policyDigest.t.buffer, 0, |
674 | 0 | session->u2.policyDigest.t.size); |
675 | | // Reset the session attributes |
676 | 0 | MemorySet(&session->attributes, 0, sizeof(SESSION_ATTRIBUTES)); |
677 | | // set the policy attribute |
678 | 0 | session->attributes.isPolicy = SET; |
679 | 0 | } |
680 | | // |
681 | | // |
682 | | // SessionCapGetLoaded() |
683 | | // |
684 | | // This function returns a list of handles of loaded session, started from input handle |
685 | | // Handle must be in valid loaded session handle range, but does not have to point to a loaded session. |
686 | | // |
687 | | // Return Value Meaning |
688 | | // |
689 | | // YES if there are more handles available |
690 | | // NO all the available handles has been returned |
691 | | // |
692 | | TPMI_YES_NO |
693 | | SessionCapGetLoaded( |
694 | | TPMI_SH_POLICY handle, // IN: start handle |
695 | | UINT32 count, // IN: count of returned handle |
696 | | TPML_HANDLE *handleList // OUT: list of handle |
697 | | ) |
698 | 34 | { |
699 | 34 | TPMI_YES_NO more = NO; |
700 | 34 | UINT32 i; |
701 | 34 | pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION); |
702 | | // Initialize output handle list |
703 | 34 | handleList->count = 0; |
704 | | // The maximum count of handles we may return is MAX_CAP_HANDLES |
705 | 34 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
706 | | // Iterate session context ID slots to get loaded session handles |
707 | 246 | for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++) |
708 | 212 | { |
709 | | // If session is active |
710 | 212 | if(gr.contextArray[i] != 0) |
711 | 0 | { |
712 | | // If session is loaded |
713 | 0 | if (gr.contextArray[i] <= MAX_LOADED_SESSIONS) |
714 | 0 | { |
715 | 0 | if(handleList->count < count) |
716 | 0 | { |
717 | 0 | SESSION *session; |
718 | | // If we have not filled up the return list, add this |
719 | | // session handle to it |
720 | | // assume that this is going to be an HMAC session |
721 | 0 | handle = i + HMAC_SESSION_FIRST; |
722 | 0 | session = SessionGet(handle); |
723 | 0 | if(session->attributes.isPolicy) |
724 | 0 | handle = i + POLICY_SESSION_FIRST; |
725 | 0 | handleList->handle[handleList->count] = handle; |
726 | 0 | handleList->count++; |
727 | 0 | } |
728 | 0 | else |
729 | 0 | { |
730 | | // If the return list is full but we still have loaded object |
731 | | // available, report this and stop iterating |
732 | 0 | more = YES; |
733 | 0 | break; |
734 | 0 | } |
735 | 0 | } |
736 | 0 | } |
737 | 212 | } |
738 | 34 | return more; |
739 | 34 | } |
740 | | // |
741 | | // |
742 | | // SessionCapGetSaved() |
743 | | // |
744 | | // This function returns a list of handles for saved session, starting at handle. |
745 | | // Handle must be in a valid handle range, but does not have to point to a saved session |
746 | | // |
747 | | // Return Value Meaning |
748 | | // |
749 | | // YES if there are more handles available |
750 | | // NO all the available handles has been returned |
751 | | // |
752 | | TPMI_YES_NO |
753 | | SessionCapGetSaved( |
754 | | TPMI_SH_HMAC handle, // IN: start handle |
755 | | UINT32 count, // IN: count of returned handle |
756 | | TPML_HANDLE *handleList // OUT: list of handle |
757 | | ) |
758 | 55 | { |
759 | 55 | TPMI_YES_NO more = NO; |
760 | 55 | UINT32 i; |
761 | 55 | pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION); |
762 | | // Initialize output handle list |
763 | 55 | handleList->count = 0; |
764 | | // The maximum count of handles we may return is MAX_CAP_HANDLES |
765 | 55 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
766 | | // Iterate session context ID slots to get loaded session handles |
767 | 405 | for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++) |
768 | 350 | { |
769 | | // If session is active |
770 | 350 | if(gr.contextArray[i] != 0) |
771 | 0 | { |
772 | | // If session is saved |
773 | 0 | if (gr.contextArray[i] > MAX_LOADED_SESSIONS) |
774 | 0 | { |
775 | 0 | if(handleList->count < count) |
776 | 0 | { |
777 | | // If we have not filled up the return list, add this |
778 | | // session handle to it |
779 | 0 | handleList->handle[handleList->count] = i + HMAC_SESSION_FIRST; |
780 | 0 | handleList->count++; |
781 | 0 | } |
782 | 0 | else |
783 | 0 | { |
784 | | // If the return list is full but we still have loaded object |
785 | | // available, report this and stop iterating |
786 | 0 | more = YES; |
787 | 0 | break; |
788 | 0 | } |
789 | 0 | } |
790 | 0 | } |
791 | 350 | } |
792 | 55 | return more; |
793 | 55 | } |
794 | | // |
795 | | // |
796 | | // SessionCapGetLoadedNumber() |
797 | | // |
798 | | // This function return the number of authorization sessions currently loaded into TPM RAM. |
799 | | // |
800 | | UINT32 |
801 | | SessionCapGetLoadedNumber( |
802 | | void |
803 | | ) |
804 | 23 | { |
805 | 23 | return MAX_LOADED_SESSIONS - s_freeSessionSlots; |
806 | 23 | } |
807 | | // |
808 | | // |
809 | | // SessionCapGetLoadedAvail() |
810 | | // |
811 | | // This function returns the number of additional authorization sessions, of any type, that could be loaded |
812 | | // into TPM RAM. |
813 | | // |
814 | | // NOTE: In other implementations, this number may just be an estimate. The only requirement for the estimate is, if it is |
815 | | // one or more, then at least one session must be loadable. |
816 | | // |
817 | | UINT32 |
818 | | SessionCapGetLoadedAvail( |
819 | | void |
820 | | ) |
821 | 23 | { |
822 | 23 | return s_freeSessionSlots; |
823 | 23 | } |
824 | | // |
825 | | // |
826 | | // SessionCapGetActiveNumber() |
827 | | // |
828 | | // This function returns the number of active authorization sessions currently being tracked by the TPM. |
829 | | // |
830 | | UINT32 |
831 | | SessionCapGetActiveNumber( |
832 | | void |
833 | | ) |
834 | 22 | { |
835 | 22 | UINT32 i; |
836 | 22 | UINT32 num = 0; |
837 | | // Iterate the context array to find the number of non-zero slots |
838 | 1.43k | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
839 | 1.40k | { |
840 | 1.40k | if(gr.contextArray[i] != 0) num++; |
841 | 1.40k | } |
842 | 22 | return num; |
843 | 22 | } |
844 | | // |
845 | | // |
846 | | // SessionCapGetActiveAvail() |
847 | | // |
848 | | // This function returns the number of additional authorization sessions, of any type, that could be created. |
849 | | // This not the number of slots for sessions, but the number of additional sessions that the TPM is capable |
850 | | // of tracking. |
851 | | // |
852 | | UINT32 |
853 | | SessionCapGetActiveAvail( |
854 | | void |
855 | | ) |
856 | 22 | { |
857 | 22 | UINT32 i; |
858 | 22 | UINT32 num = 0; |
859 | | // Iterate the context array to find the number of zero slots |
860 | 1.43k | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
861 | 1.40k | { |
862 | 1.40k | if(gr.contextArray[i] == 0) num++; |
863 | 1.40k | } |
864 | 22 | return num; |
865 | 22 | } |