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